package nc.impl.hrpbm.budgetmake.budgetmake;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

import nc.impl.hrpbm.budgetreply.budgetreply.CGFourWriteBakDataUtil;
import nc.impl.pubapp.pattern.data.bill.BillQuery;
import nc.vo.am.common.util.StringUtils;
import nc.vo.hrppl.pjapplication.AggPjapplVO;
import nc.vo.pub.VOStatus;
import java.util.List;

import nccloud.commons.lang.ArrayUtils;
import nccloud.hrpbm.budget.util.ValidateProject;
import nccloud.hrpbm.budget.util.CountGovAndAssetMoney;
import nccloud.base.exception.ExceptionUtils;
import nc.vo.pmpub.project.ProjectHeadVO;
import nc.vo.uapbd.funsource.FundSourceVO;
import nc.bs.lcdp.dao.LcdpDAO;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import nc.vo.lcdp.pub.aggvo.MetaDataBaseVO;
import java.util.stream.Stream;
import nc.bs.dao.BaseDAO;
import nc.bs.dao.DAOException;
import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.hrpbm.budgetmake.util.CheckAboutHrppl;
import nc.bs.hrpbm.statemanage.TaskStateManager;
import nc.bs.util.DefdocUtils;
import nc.codeplatform.framework.service.ServiceSupport;
import nc.hrpbm.utils.CalculationFormulaUtils;
import nc.impl.pub.util.db.InSqlManager;
import nc.impl.pubapp.pattern.data.vo.VOQuery;
import nc.itf.hrpbm.budgetcalculate.budgetcalculatemaster.IBudgetcalculateVOService;
import nc.itf.hrpbm.budgetperformancegoals.budgetperformancegoalsmaster.IBudgetPerformanceGoalsMasterVOService;
import nc.itf.hrpbm.budgetindicator.budgetindicatorvo.IBudgetIndicatorVOService;
import nc.itf.hrpbm.budgetmake.budgetmake.IBudgetMakeVOService;
import nc.itf.hrpbm.budgetreply.budgetreply.IBudgetReplyVOService;
import nc.itf.hrpbm.budgetscheme.budgetscheme.IBudgetSchemeVOService;
import nc.itf.hrpbm.budgettask.budgettask.IBudgettaskService;
import nc.itf.hrpbm.budgettype.budgettype.IBudgettypeService;
import nc.itf.hrpbm.operationalindicator.operationalindicator.IOperationalindicatorMasterVOService;
import nc.jdbc.framework.generator.SequenceGenerator;
import nc.jdbc.framework.processor.BeanListProcessor;
import nc.jdbc.framework.processor.ColumnProcessor;
import nc.jdbc.framework.processor.MapListProcessor;
import nc.pub.billcode.vo.BillCodeContext;
import nc.pubitf.rbac.IDataPermissionPubService;
import nc.vo.bc.pub.util.VOEntityUtil;
import nc.jdbc.framework.processor.ColumnListProcessor;
import nc.ms.outsys.util.IntegerProcessor;
import nc.pubitf.bd.accessor.GeneralAccessorFactory;
import nc.pubitf.bd.accessor.IGeneralAccessor;
import nc.vo.bd.accessor.IBDData;
import nc.vo.bd.inoutbusiclass.InoutBusiClassVO;
import nc.vo.bd.period2.AccperiodmonthVO;
import nc.vo.hrpbctp.busictrl.BusiCtrlDataVO;
import nc.vo.hrpbctp.ctrldim.CtrlDimVO;
import nc.vo.hrpbm.FormulaInfoVO;
import nc.vo.hrpbm.SplitRowCopyItems;
import nc.vo.hrpbm.budgetcalculate.AggBudgetcalculateMasterVO;
import nc.vo.hrpbm.budgetcalculate.BudgetcalculateSlaveVO;
import nc.vo.hrpbm.budgetcalculate.CalculateItems;
import nc.vo.hrpbm.budgetindicator.AggBudgetIndicatorVO;
import nc.vo.hrpbm.budgetindicator.BudgetIndicatorBVO;
import nc.vo.hrpbm.budgetmake.AggBudgetMakeVO;
import nc.vo.hrpbm.budgetmake.AssetAllocationVO;
import nc.vo.hrpbm.budgetmake.BudgetMakeDetailVO;
import nc.vo.hrpbm.budgetmake.BudgetMakeVO;
import nc.vo.hrpbm.budgetmake.CopyBudgetMakeVO;
import nc.vo.hrpbm.budgetmake.GovpurchVO;
import nc.vo.hrpbm.budgetperformancegoals.BudgetPerformanceGoalsMasterVO;
import nc.vo.hrpbm.budgetmake.SpBudgetMakeDetailVO;
import nc.vo.hrpbm.budgetreply.AggBudgetReplyVO;
import nc.vo.hrpbm.budgetreply.AssetAllocationReplyVO;
import nc.vo.hrpbm.budgetreply.BudgetReplyDetailVO;
import nc.vo.hrpbm.budgetreply.BudgetReplyVO;
import nc.vo.hrpbm.budgetreply.GovpurchReplyVO;
import nc.vo.hrpbm.budgetreply.SpBudgetReplyDetailVO;
import nc.vo.hrpbm.budgetscheme.AggBudgetSchemeVO;
import nc.vo.hrpbm.budgettask.Budgettask;
import nc.vo.hrpbm.budgettype.Budgettype;
import nc.vo.hrpbm.hrpbmpubenum.IndicatorDimEnum;
import nc.vo.hrpbm.hrpbmpubenum.TaskProcessEnum;
import nc.vo.hrpbm.hrpbmpubenum.TaskStageEnum;
import nc.vo.hrpbm.hrpbmpubenum.TaskStateEnum;
import nc.vo.hrpbm.hrpcontrolbaseenum.BmBmindicatorCtrlTypeEnum;
import nc.vo.hrpbm.operationalindicator.OperationalindicatorMasterVO;
import nc.vo.hrpbm.reportfunds.ReportfundsSlaveVO;
import nc.vo.ml.NCLangRes4VoTransl;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.ISuperVO;
import nc.vo.pub.SuperVO;
import nc.vo.pub.billtype.BilltypeVO;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pub.pf.BillStatusEnum;
import nc.vo.pubapp.AppContext;
import nc.vo.pubapp.billtype.BillTypeQueryTools;
import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill;
import nc.vo.pubapp.pattern.pub.SqlBuilder;
import nccloud.hrpbm.budget.util.BudgetCalUtil;
import nccloud.hrpbm.budget.util.GenerateBudgetNo;
import nccloud.hrpbm.budget.util.GetIdCode;
import nccloud.hrpbm.budget.util.SetChildColumnValue;
import nccloud.hrpbm.budget.util.ValidateAssetAllocation;
import nccloud.hrpbm.budget.util.ValidateBudgetDetail;
import nccloud.hrpbm.budget.util.ValidateChildLength;
import nccloud.hrpbm.budget.util.ValidateOtherTwoChildLength;
import nccloud.pubitf.riart.pflow.CloudPFlowContext;
import nccloud.impl.hrpbm.pub.common.HrpbmServiceSupport;
import nccloud.itf.hrpbm.pub.common.IHrpbmCommonService;
import org.apache.poi.ss.formula.functions.T;

public class BudgetMakeVOServiceImpl extends ServiceSupport implements IBudgetMakeVOService {
	//过滤停用档案的行，项目、收支项目、资金来源、业务指标、defdim1~10
	private static final String[] dimFields = {"pk_project","pk_inoutclass", "pk_fundsource","pk_operation",
			"defdim1", "defdim2", "defdim3", "defdim4", "defdim5", "defdim6", "defdim7", "defdim8", "defdim9", "defdim10"};
	TaskStateManager taskStateManager = new TaskStateManager();

	private final String[] queryHisDataTopcode = { "YS02", "YS03", "YS04", "YS05", "YS06" };

	private final String[] queryHisDataFormulas = { "amount", "execnum" };

	IOperationalindicatorMasterVOService operationalindicatorMasterVOService = NCLocator
			.getInstance().lookup(IOperationalindicatorMasterVOService.class);
	IHrpbmCommonService iHrpbmCommonService = NCLocator.getInstance().lookup(IHrpbmCommonService.class);

	private Map<String, Object> formulaValues;

	public AggBudgetMakeVO[] listAggBudgetMakeVOByPk(String... pks) throws BusinessException {
		return listAggBudgetMakeVOByPk(false, pks);
	}

	public AggBudgetMakeVO[] listAggBudgetMakeVOByPk(boolean blazyLoad, String... pks) throws BusinessException {
		return this.dao.listByPksWithOrder(AggBudgetMakeVO.class, pks, blazyLoad);
	}

	public AggBudgetMakeVO findAggBudgetMakeVOByPk(String pk) throws BusinessException {
		return this.dao.findByPk(AggBudgetMakeVO.class, pk, false);
	}

	public AggBudgetMakeVO[] listAggBudgetMakeVOByCondition(String condition) throws BusinessException {
		return listAggBudgetMakeVOByCondition(condition, new String[] { "pk_budgetmake" });
	}

	public AggBudgetMakeVO[] listAggBudgetMakeVOByCondition(String condition, String[] orderPath)
			throws BusinessException {
		return this.dao.listByCondition(AggBudgetMakeVO.class, condition, false, false, orderPath);
	}

	public BudgetMakeVO[] listBudgetMakeVOByPk(String... pks) throws BusinessException {
		return this.dao.listByPk(BudgetMakeVO.class, pks, true);
	}

	public BudgetMakeVO findBudgetMakeVOByPk(String pk) throws BusinessException {
		return this.dao.findByPk(BudgetMakeVO.class, pk, true);
	}

	public BudgetMakeVO[] listBudgetMakeVOByCondition(String condition) throws BusinessException {
		return listBudgetMakeVOByCondition(condition, new String[] { "dbilldate" });
	}

	public BudgetMakeVO[] listBudgetMakeVOByCondition(String condition, String[] orderPath) throws BusinessException {
		return this.dao.listByCondition(BudgetMakeVO.class, condition, false, false, orderPath);
	}

	public String[] listBudgetMakeVOPkByCond(String condition) throws BusinessException {
		return listBudgetMakeVOPkByCond(condition, new String[] { "dbilldate" });
	}

	public String[] listBudgetMakeVOPkByCond(String condition, String[] orderPath) throws BusinessException {
		IDataPermissionPubService service = NCLocator.getInstance()
				.lookup(IDataPermissionPubService.class);
		String wheresql = service.getDataRefSQLWherePart(AppContext.getInstance().getPkUser(),
				AppContext.getInstance().getPkGroup(), "hrpbm_budgetdept", "default", "hrpbm_budgetdept");
		if (StringUtils.isEmpty(condition)) {
			condition = " 1 = 1 ";
		}
		if (Objects.nonNull(wheresql)) {
			condition = condition + " and pk_budgetdept in ( select pk_budgetdept from hrpbm_budgetdept where "
					+ wheresql + " )";
		}

		BudgetMakeVO[] vos = this.dao.listByCondition(BudgetMakeVO.class, condition, false, false, orderPath);
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		String[] pks = new String[vos.length];
		for (int start = 0, end = vos.length - 1; start <= vos.length - 1; start++, end--) {
			pks[start] = vos[end].getPrimaryKey();
		}
		return pks;
	}

	public void initDefaultData(BudgetMakeVO vo) {
		if (vo.getAttributeValue("pk_group") == null) {
			vo.setAttributeValue("pk_group", InvocationInfoProxy.getInstance().getGroupId());
		}
		if (vo.getAttributeValue("billmaker") == null) {
			vo.setAttributeValue("billmaker", InvocationInfoProxy.getInstance().getUserId());
		}
		if (vo.getAttributeValue("billmaketime") == null) {
			vo.setAttributeValue("billmaketime", new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime()));
		}
		if (vo.getAttributeValue("billtype") == null) {
			vo.setAttributeValue("billtype", "BM20");
		}
		if (vo.getAttributeValue("taskstate") == null) {
			vo.setAttributeValue("taskstate", Integer.valueOf(1));
		}
		if (vo.getAttributeValue("taskstage") == null) {
			vo.setAttributeValue("taskstage", Integer.valueOf(1));
		}
		if (vo.getAttributeValue("dbilldate") == null) {
			vo.setAttributeValue("dbilldate", new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime()));
		}
		if (vo.getAttributeValue("approvestatus") == null) {
			vo.setAttributeValue("approvestatus", Integer.valueOf(-1));
		}
	}


	/*
    一下批复生成二上编制单时，把一上编制单的制单人及创建人带到二上编制单中
     */
	public void initDefaultData(BudgetMakeVO vo,BudgetReplyVO replyVO) throws BusinessException {
		AggBudgetMakeVO[] firstBill = this.listAggBudgetMakeVOByPk(replyVO.getPk_firstupbill());
		if(Objects.nonNull(firstBill) && firstBill.length > 0){
			BudgetMakeVO parentVO = firstBill[0].getParentVO();
			vo.setCreator(parentVO.getCreator());
			vo.setBillmaker(parentVO.getBillmaker());
		}

		if (vo.getAttributeValue("pk_group") == null) {
			vo.setAttributeValue("pk_group", InvocationInfoProxy.getInstance().getGroupId());
		}
		if (vo.getAttributeValue("billmaketime") == null) {
			vo.setAttributeValue("billmaketime", new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime()));
		}
		if (vo.getAttributeValue("billtype") == null) {
			vo.setAttributeValue("billtype", "BM20");
		}
		if (vo.getAttributeValue("taskstate") == null) {
			vo.setAttributeValue("taskstate", 1);
		}
		if (vo.getAttributeValue("taskstage") == null) {
			vo.setAttributeValue("taskstage", 1);
		}
		if (vo.getAttributeValue("dbilldate") == null) {
			vo.setAttributeValue("dbilldate", new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime()));
		}
		if (vo.getAttributeValue("approvestatus") == null) {
			vo.setAttributeValue("approvestatus", BillStatusEnum.FREE.toIntValue());
		}
	}
	public void initTransTypeData(BudgetMakeVO vo, Map<String, String> resultMap) {
		if (vo.getAttributeValue("transtype") == null) {
			vo.setAttributeValue("transtypepk", resultMap.get("transtypepk"));
			vo.setAttributeValue("transtype", resultMap.get("transtypecode"));
		}
	}

	public AggBudgetMakeVO preAddAggBudgetMakeVO(AggBudgetMakeVO vo, Map<String, Object> userJson,
												 Map<String, String> resultMap) throws BusinessException {
		getMainVO(vo).setStatus(2);
		initDefaultData((BudgetMakeVO) getMainVO(vo));

		if (resultMap != null) {
			initTransTypeData((BudgetMakeVO) getMainVO(vo), resultMap);
		}

		Map<String, String> data = (userJson != null && userJson.get("data") != null) ? (Map) userJson.get("data")
				: null;

		if (data != null && data.size() > 0) {
			String parentKey = data.get("parentKey");
			String parentPk = data.get("parentPk");
			getMainVO(vo).setAttributeValue(parentKey, parentPk);
		}

		// 编码规则生成vo的编码
		BillCodeContext billCodeContext = getBillCodeContext("hrpbmbudgetmake");
		if (billCodeContext == null) {
			throw new BusinessException("当前编码规则不存在，请到【编码规则定义-全局】节点检查是否存在hrpbmbudgetmake");
		}
		if (billCodeContext.isPrecode()) {
			String pk_group = InvocationInfoProxy.getInstance().getGroupId();
			String code = getBillcodeManage().getPreBillCode_RequiresNew("hrpbmbudgetmake", pk_group, pk_group);
			getMainVO(vo).setAttributeValue("billno", code);
		}

		return vo;
	}

	public AggBudgetMakeVO preAddAggBudgetMakeVO(Map<String, Object> userJson, Map<String, String> resultMap)
			throws BusinessException {
		AggBudgetMakeVO result = null;

		BudgetMakeVO mainvo = new BudgetMakeVO();
		// 设置默认值
		initDefaultData(mainvo);
		AggBudgetMakeVO aggvo = new AggBudgetMakeVO();
		aggvo.setParent(mainvo);
		result = aggvo;
		return preAddAggBudgetMakeVO(result, userJson, resultMap);
	}

	public AggBudgetMakeVO preEditAggBudgetMakeVO(String pk) throws BusinessException {
		return this.dao.findByPk(AggBudgetMakeVO.class, pk, false);
	}

	public AggBudgetMakeVO[] saveAggBudgetMakeVO(AggBudgetMakeVO vo) throws BusinessException {
		// modify 补丁适配增加暂存功能
		UFBoolean tempsave = Objects.nonNull(vo.getParentVO().getTempsave()) ? vo.getParentVO().getTempsave()
				: UFBoolean.FALSE;
		String pk = getVOPrimaryKey(vo);
		Integer taskCom = Integer.valueOf(-1);
		//表头新加的政府采购预算合计金额，资产配置预算合计金额在保存时计算更新保存。导入后重新计算得出合计金额。
		CountGovAndAssetMoney.count(vo, GovpurchVO.class, AssetAllocationVO.class);
		if (tempsave.booleanValue()) {
			if (StringUtils.isEmpty(pk)) {
				setBillCode(vo);
				setAuditInfo(vo);
				vo.getParentVO().setTempsave(tempsave);
				AggBudgetMakeVO[] aggBudgetMakeVOs = dao.insert(vo);
				return aggBudgetMakeVOs; // 插入
			} else {
				AggBudgetMakeVO[] aggBudgetMakeVOs = dao.update(vo);
				return aggBudgetMakeVOs; // 更新
			}
		} else {

			if (vo.getParentVO().getTaskstate().equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {
				taskCom = Integer.valueOf(TaskStateEnum.Complete.toIntValue());
			}

			ValidateChildLength.validateChildLength(vo);

			if (!vo.getParentVO().getTranstype().contains("BD")
					&& (vo.getParentVO().getTranstype().contains("YS02")
					|| vo.getParentVO().getTranstype().contains("YS04")
					|| vo.getParentVO().getTranstype().contains("YS03"))
					&& (Objects.nonNull(vo.getChildren(GovpurchVO.class))
					|| Objects.nonNull(vo.getChildren(AssetAllocationVO.class)))) {
				StringBuffer errmsg = new StringBuffer();
				// 验证政府采购和资产分配页签是否必输
				ValidateOtherTwoChildLength.validateChildLength(vo, BudgetMakeDetailVO.class, GovpurchVO.class, AssetAllocationVO.class,errmsg);

				//6.新增资产中项目合计“金额”要小于等于政采中对应项目的合计“金额”。否则给出提示：**项目，新增资产预算不能大于政府采购预算，请修改，不允许保存。导入也同步验证。
				ValidateOtherTwoChildLength.validateChildLength(vo, BudgetMakeDetailVO.class, GovpurchVO.class,
						AssetAllocationVO.class, errmsg);


				// 校验资产配置页签必输项
				ValidateAssetAllocation.check((SuperVO[]) vo.getChildren(AssetAllocationVO.class), errmsg);
				if (errmsg.length() > 0) {
					throw new BusinessException(errmsg.toString());
				}
			}
		}

		// 预算任务中编制流程为审核生效，流程状态单独处理
		String pk_budgettask = vo.getParentVO().getPk_budgettask();
		// 验证政府采购和资产分配页签是否必输
		Budgettask budgettask = NCLocator.getInstance().lookup(IBudgettaskService.class)
				.findBudgettaskByPk(pk_budgettask);
		if (budgettask.getTaskprocess().equals(Integer.valueOf(TaskProcessEnum.ApproveSuccess.toIntValue()))) {
			vo.getParentVO().setTaskstate(Integer.valueOf(TaskStateEnum.ApproveComplete_add.toIntValue()));
			vo.getParentVO().setTaskstage(Integer.valueOf(TaskStageEnum.ApproveSuccess.toIntValue()));
		}

		setDefaultVal(vo);


		// 计算子表vhashcode
		GetIdCode.getIdCode((CircularlyAccessibleValueObject[]) vo.getChildren(BudgetMakeDetailVO.class));


		// 表体引用了项目库项目并开启相关参数则进行校验
		CheckAboutHrppl.check_budgetMake(vo);

		if (StringUtils.isEmpty(pk)) {
			AggBudgetMakeVO[] aggBudgetMakeVOs = this.dao.insert(vo);
			// 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
			ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
			validateBudgetDetail.validateBudgetDetail(aggBudgetMakeVOs[0], BudgetMakeDetailVO.getDefaultTableName(),
					"pk_budgetmakedetail");
			// 子表数据如果有srcbillid则回写科室上报归口的hassummary和pk_summarybill
			rewriteDeptReportByPks(aggBudgetMakeVOs);
			return aggBudgetMakeVOs;
		}
		// modidy by wy at 2207适配930
		else{
			// 修改保存前处理编制状态
			if (budgettask.getTaskprocess().equals(Integer.valueOf(TaskProcessEnum.ApproveSuccess.toIntValue()))) {
				vo.getParentVO().setTaskstate(Integer.valueOf(TaskStateEnum.ApproveComplete_add.toIntValue()));
			} else {
				vo = (AggBudgetMakeVO) this.taskStateManager.taskStateProcess(vo, "ADD", false, false);
			}

			if (taskCom.intValue() != -1) {


				vo.getParentVO().setTaskstate(taskCom);
			}
			AggBudgetMakeVO[] aggBudgetMakeVOs = this.dao.update(vo);
			// 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
			ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
			validateBudgetDetail.validateBudgetDetail(aggBudgetMakeVOs[0], BudgetMakeDetailVO.getDefaultTableName(),
					"pk_budgetmakedetail");
			// 子表数据如果有srcbillid则回写科室上报归口的hassummary和pk_summarybill
			rewriteDeptReportByPks(aggBudgetMakeVOs);
			return aggBudgetMakeVOs;
		}
	}

	/**
	 * 子表数据如果有srcbillid则回写科室上报归口的hassummary和pk_summarybill
	 *
	 * @throws BusinessException
	 */
	private void rewriteDeptReportByPks(AggBudgetMakeVO[] aggvos) throws BusinessException {
		for (AggBudgetMakeVO aggvo : aggvos) {
			CircularlyAccessibleValueObject[] vos = aggvo.getAllChildrenVO();
			List<String> pks = new ArrayList<>();
			if (Objects.nonNull(aggvo.getParentVO().getSummarybills())) {
				String[] summarybills = aggvo.getParentVO().getSummarybills().split(",");
				Collections.addAll(pks, summarybills);
			}
			if (!pks.isEmpty()) {
				VOQuery<BudgetMakeVO> budgetmakeQuery = new VOQuery<BudgetMakeVO>(BudgetMakeVO.class);
				BudgetMakeVO[] budgetMakeVOs = budgetmakeQuery.query(pks.toArray(new String[0]));
				for (BudgetMakeVO budgetMakeVO : budgetMakeVOs) {
					budgetMakeVO.setHassummary(UFBoolean.TRUE);
					budgetMakeVO.setPk_summarybill(aggvo.getParentVO().getPk_budgetmake());
				}
				this.dao.update(budgetMakeVOs);
			}
		}
	}

	/**
	 * 保存前处理编码规则
	 *
	 * @param vos
	 */
	private void setBillCode(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isNotEmpty(vos)) {
			for (AggBudgetMakeVO vo : vos) {
				String pk = getVOPrimaryKey(vo);
				if (StringUtils.isEmpty(pk)) {
					BillCodeContext billCodeContext = getBillCodeContext("hrpbmbudgetmake");
					String pk_group = InvocationInfoProxy.getInstance().getGroupId();
					if (billCodeContext != null && !billCodeContext.isPrecode()) {
						if (getMainVO(vo).getAttributeValue("billno") == null) {
							String code = getBillcodeManage().getBillCode_RequiresNew("hrpbmbudgetmake", pk_group,
									pk_group, getMainVO(vo));
							getMainVO(vo).setAttributeValue("billno", code);
						}
					} else {
						String code = (String) getMainVO(vo).getAttributeValue("billno");
						getBillcodeManage().commitPreBillCode("hrpbmbudgetmake", pk_group, pk_group, code);
					}
				}
			}
		}
	}

	/**
	 * 保存前设置审计信息
	 *
	 * @param vos
	 */
	private void setAuditInfo(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isNotEmpty(vos)) {
			UFDateTime now = new UFDateTime();
			for (AggBudgetMakeVO vo : vos) {
				String pk = getVOPrimaryKey(vo);
				if (StringUtils.isEmpty(pk)) {
					// 设置创建人创建时间
					if(null == getMainVO(vo).getAttributeValue("creator")){
						//一下批复生成二上编制单时，把一上编制单的制单人及创建人带到二上编制单中
						getMainVO(vo).setAttributeValue("creator", InvocationInfoProxy.getInstance().getUserId());
					}
					getMainVO(vo).setAttributeValue("creationtime", now);
					getMainVO(vo).setAttributeValue("billmaketime", now);
				} else {
					// 设置修改人修改时间
					getMainVO(vo).setAttributeValue("modifier", InvocationInfoProxy.getInstance().getUserId());
					getMainVO(vo).setAttributeValue("modifiedtime", now);
					getMainVO(vo).setAttributeValue("lastmaketime", now);
				}
			}
		}
	}

	/**
	 * 保存前处理一些默认值
	 *
	 * @param vos
	 */
	private void setDefaultVal(AggBudgetMakeVO... vos) throws BusinessException {
		setBillCode(vos);
		setAuditInfo(vos);
		// 其他默认值处理
		// 生成预算号
		GenerateBudgetNo generateBudgetNo = new GenerateBudgetNo();
		generateBudgetNo.generateBudgetNo(vos);
		// 表头年度、编制科室、预算类型赋值给表体字段
		SetChildColumnValue.setChildColumnValue(vos, true);
		// 回写合计金额
		GettotalMny(vos);
	}

	private void GettotalMny(AggBudgetMakeVO... vos) throws BusinessException {
		for (AggBudgetMakeVO aggVo : vos) {
			aggVo.getParentVO().setTotalamount(UFDouble.ZERO_DBL);
			BudgetMakeDetailVO[] detailVOs = (BudgetMakeDetailVO[]) aggVo.getChildren(BudgetMakeDetailVO.class);
			UFDouble totalMny = UFDouble.ZERO_DBL;
			for (BudgetMakeDetailVO detailVO : detailVOs) {
				if (aggVo.getParentVO().getTaskstage()
						.equals(Integer.valueOf(TaskStageEnum.ApproveSuccess.toIntValue()))) {
					detailVO.setAmount_firstup(detailVO.getAmount_seconddown());
				}
				if ((aggVo.getParentVO().getTaskstage().equals(Integer.valueOf(TaskStageEnum.FirstUp.toIntValue()))
						|| aggVo.getParentVO().getTaskstage()
						.equals(Integer.valueOf(TaskStageEnum.ApproveSuccess.toIntValue())))
						&& Objects.nonNull(detailVO.getAmount_firstup()) && detailVO.getStatus() != 3) {
					totalMny = totalMny.add(new UFDouble(detailVO.getAmount_firstup()));
				}

				if (aggVo.getParentVO().getTaskstage().equals(Integer.valueOf(TaskStageEnum.SecondUp.toIntValue()))
						&& Objects.nonNull(detailVO.getAmount_secondup()) && detailVO.getStatus() != 3) {
					totalMny = totalMny.add(new UFDouble(detailVO.getAmount_secondup()));
				}
			}

			aggVo.getParentVO().setTotalamount(totalMny);
		}
	}

	// 给单表（行编辑表）单独适配
	public AggBudgetMakeVO[] saveAggBudgetMakeVO(AggBudgetMakeVO[] vos) throws BusinessException {
		setDefaultVal(vos);
		return this.dao.save(vos, true);
	}

	public AggBudgetMakeVO[] deleteAggBudgetMakeVOs(Map<String, String> tsMap, boolean isFromServer)
			throws BusinessException {
		AggBudgetMakeVO[] vos = this.dao.listByPk(AggBudgetMakeVO.class,
				tsMap.keySet().toArray(new String[0]));
		validate(vos, tsMap, isFromServer);
		String pk_group = InvocationInfoProxy.getInstance().getGroupId();
		Arrays.stream(vos).forEach(vo -> {
			String code = (String) getMainVO(vo).getAttributeValue("billno");
			try {
				getBillcodeManage().returnBillCodeOnDelete("hrpbmbudgetmake", pk_group, pk_group, code, vo);
			} catch (BusinessException e) {
				e.printStackTrace();
			}
		});
		this.dao.delete(vos, true);
		return vos;
	}


	// 校验 包括ts校验
	private void validate(AggBudgetMakeVO[] vos, Map<String, String> tsMap, boolean isFromServer)
			throws BusinessException {
		Boolean isPass = Boolean.valueOf(true);
		Boolean canDel = Boolean.valueOf(false);
		Boolean isDeptUp = Boolean.valueOf(false);
		if (ArrayUtils.isEmpty(vos)) {
			isPass = Boolean.valueOf(false);
		}
		for (AggBudgetMakeVO vo : vos) {

			BudgetMakeVO budgetMakeVO = vo.getParentVO();
			UFDateTime ts = (UFDateTime) budgetMakeVO.getAttributeValue("ts");
			if (!StringUtils.equals(tsMap.get(budgetMakeVO.getPrimaryKey()), ts.toString())) {
				isPass = Boolean.valueOf(false);
				break;
			}
			if (!budgetMakeVO.getAttributeValue("taskstate").equals(TaskStateEnum.FirstUpMake.value())
					&& !budgetMakeVO.getAttributeValue("taskstate").equals(TaskStateEnum.ApproveComplete_add.value())) {
				canDel = Boolean.valueOf(true);

				break;
			}
			// modify by wy at 2207适配930
			//if (Objects.nonNull(vo.getParentVO().getSummarybills())) {
			//	isDeptUp = Boolean.valueOf(true);
			//}

			String condition = " pk_summarybill = '"+vo.getParentVO().getPk_budgetmake()+"' and HASSUMMARY = 'Y'";
			BudgetMakeVO[] summarybills = this.listBudgetMakeVOByCondition(condition);
			if (Objects.nonNull(summarybills) && summarybills.length>0) {
				isDeptUp = true;
			}
		}

		if (!isPass.booleanValue()) {
			throw new BusinessException("您操作的数据已被他人修改或删除，请刷新后重试！");
		}
		if (canDel.booleanValue() && !isFromServer) {
			throw new BusinessException("只有任务状态为一上编制时，可以删除！");
		}
		if (isDeptUp.booleanValue()) {
			throw new BusinessException("已汇总单据，必须取消汇总才能删除。");
		}
	}

	public <T> T[] loadTreeData(Class<T> clazz, Map<String, Object> userJson) throws BusinessException {
		return this.dao.listByCondition(clazz, " dr = 0 ", false);
	}

	public String[] queryChildPksByParentId(Class childClazz, String parentId) throws BusinessException {
		String cond = " pk_budgetmake = '" + parentId + "' ";
		SuperVO[] vos = (SuperVO[]) this.dao.listByCondition(childClazz, cond, false);
		if (vos == null || vos.length == 0) {
			return new String[0];
		}
		return Stream.of(vos).map(vo -> vo.getPrimaryKey()).toArray(String[]::new);
	}

	public SuperVO[] queryChildVOByPks(Class childClazz, String[] pks) throws BusinessException {
		if (pks.length == 0) {
			return null;
		}
		VOQuery<BudgetMakeDetailVO> detailQuery = new VOQuery<BudgetMakeDetailVO>(BudgetMakeDetailVO.class);
		SqlBuilder sql = new SqlBuilder();
		sql.append(" and ");
		sql.append("pk_budgetmakedetail", pks);
		String ordersql = " order by BUDGETNO";
		BudgetMakeDetailVO[] vos = detailQuery.query(sql.toString(), ordersql);
		if (childClazz.isInstance(BudgetMakeDetailVO.class)) {
			return vos;
		}
		return (SuperVO[]) this.dao.listByPk(childClazz, pks, false);
	}


	/**
	 * 提交前校验: 检查单据状态
	 *
	 * @throws BusinessException
	 */
	private void validateCommitAggBudgetMakeVO(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return;
		}
		List<AggBudgetMakeVO> list = Arrays.stream(vos).filter(item -> (item.getParentVO() != null))
				.filter(item -> {
					Integer status = (Integer) item.getParentVO().getAttributeValue("approvestatus");
					return (status == null || (status.intValue() != BillStatusEnum.FREE.toIntValue()
							&& status.intValue() != BillStatusEnum.NOPASS.toIntValue()));
				}).map(item -> item).collect(Collectors.toList());

		List<AggBudgetMakeVO> tempsaveList = Arrays.stream(vos).filter(item -> item.getParentVO() != null).filter(item -> {
			UFBoolean tempsave = item.getParentVO().getTempsave();
			return tempsave != null && tempsave.booleanValue() ;
		}).map(item -> item).collect(Collectors.toList());

		//一上预算提交也要验证是否录入绩效目标，否则不允许提交。因为客户预算要导入，导入并没有导绩效指标。
		StringBuffer errmsg = new StringBuffer();
		StringBuffer warning = new StringBuffer();
		List<AbstractBill> validatePorjectList = new ArrayList<>();
		ValidateProject validateProject = new ValidateProject();
		for (AggBudgetMakeVO aggvo:vos
		) {
			List<AbstractBill> result = validateProject.validateProject(aggvo, BudgetMakeDetailVO.class,errmsg,warning);
			validatePorjectList.addAll(result);
		}

		if ((list == null || list.size() == 0) && (tempsaveList == null || tempsaveList.size() == 0) && (validatePorjectList == null || validatePorjectList.size() == 0)) {
			return;
		}
		String errors = "";
		for (AggBudgetMakeVO vo : list) {
			errors = errors + "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：单据状态不正确，请检查。\n";
		}
		for (AggBudgetMakeVO vo : tempsaveList){
			errors += "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：暂存单据不能提交。\n";
		}
		for (AbstractBill vo : validatePorjectList){
			errors += "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：有未录入的绩效目标的项目。\n";
		}
		if (errmsg.length() > 0 ){
			errors += errmsg.toString();
		}
		throw new BusinessException(errors);
	}

	/**
	 * 收回前校验: 检查单据状态
	 *
	 * @throws BusinessException
	 */
	private void validateUnCommitAggBudgetMakeVO(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return;
		}
		List<AggBudgetMakeVO> list = Arrays.stream(vos).filter(item -> (item.getParentVO() != null))
				.filter(item -> {
					Integer status = (Integer) item.getParentVO().getAttributeValue("approvestatus");
					return (status == null || status.intValue() == BillStatusEnum.FREE.toIntValue());
				}).map(item -> item).collect(Collectors.toList());

		if (list == null || list.size() == 0) {
			return;
		}
		String errors = "";
		for (AggBudgetMakeVO vo : list) {
			errors = errors + "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：单据状态不正确，请检查。\n";
		}
		throw new BusinessException(errors);
	}

	public Map<String, Object> commitAggBudgetMakeVO(String actionName, Map<String, String> tsMap, Object assign)
			throws BusinessException {
		BillQuery<AggBudgetMakeVO> billQuery = new BillQuery<AggBudgetMakeVO>(AggBudgetMakeVO.class);
		AggBudgetMakeVO[] vos = billQuery.query(getAllPks(tsMap));
//		AggBudgetMakeVO[] vos = this.dao.listByPk(AggBudgetMakeVO.class, getAllPks(tsMap), true); // 项目预算编制二上编报提交报错  local3
		validateTs(tsMap, vos);
		// 提交前校验及业务逻辑
		validateCommitAggBudgetMakeVO(vos);
		Map<String, Object> res = this.execFlows(actionName, "BM20", assign, vos);
		// 提交后业务逻辑
		return res;
	}

	protected Map<String, Object> execFlows(String actionName, String pk_billtype, Object assign, Object... vos)
			throws BusinessException {
		if (StringUtils.isEmpty(pk_billtype)) {
			throw new BusinessException(NCLangRes4VoTransl.getNCLangRes().getStrByID("codebase", "0codebase0000"));
		}

		AggregatedValueObject[] aggvos = adpterVO2Agg(vos);
		CloudPFlowContext[] context = this.flowUtils.createContext(aggvos, actionName, pk_billtype);

		if (assign != null && context != null && context.length == 1) {
			Map<Object, Object> param = (context[0].geteParam() == null) ? new HashMap() : context[0].geteParam();
			param.put("content", assign);
			context[0].seteParam(param);
		}

		return this.flowUtils.execApplyFlow(context);
	}

	public void batchCommitAggBudgetMakeVO(String actionName, Map<String, String> tsMap) throws BusinessException {
		AggBudgetMakeVO[] vos = this.dao.listByPk(AggBudgetMakeVO.class, getAllPks(tsMap), true);
		validateTs(tsMap, vos);
		// 批量提交前校验及业务逻辑
		validateCommitAggBudgetMakeVO(vos);
		Map<String, Object> res = execFlows(actionName, "BM20", vos);
		// 批量提交后业务逻辑
	}

	public AggBudgetMakeVO uncommitAggBudgetMakeVO(String actionName, Map<String, String> tsMap)
			throws BusinessException {
		AggBudgetMakeVO[] vos = this.dao.listByPk(AggBudgetMakeVO.class, getAllPks(tsMap), true);
		validateTs(tsMap, vos);
		// 收回前校验及业务逻辑
		validateUnCommitAggBudgetMakeVO(vos);
		Map<String, Object> res = execFlows(actionName, "BM20", vos);
		// 收回后业务逻辑
		return vos[0];
	}

	public void batchUncommitAggBudgetMakeVO(String actionName, Map<String, String> tsMap) throws BusinessException {
		AggBudgetMakeVO[] vos = this.dao.listByPk(AggBudgetMakeVO.class, getAllPks(tsMap), true);
		validateTs(tsMap, vos);
		// 批量收回前校验及业务逻辑
		validateUnCommitAggBudgetMakeVO(vos);
		Map<String, Object> res = execFlows(actionName, "BM20", vos);
		// 批量收回后业务逻辑
	}

	public AggBudgetMakeVO[] callbackSAVEBASE(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetMakeVO> update = new ArrayList<AggBudgetMakeVO>(), insert = new ArrayList<AggBudgetMakeVO>();
		for (AggBudgetMakeVO item : vos) {
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}
		List<AggBudgetMakeVO> ret = new ArrayList<AggBudgetMakeVO>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.insert(insert.toArray(new AggBudgetMakeVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.update(update.toArray(new AggBudgetMakeVO[0]))));
		}
		return ret.toArray(new AggBudgetMakeVO[0]);
	}

	public AggBudgetMakeVO[] callbackSAVE(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		Arrays.stream(vos).forEach(v -> v.getParent().setAttributeValue("approvestatus", Integer.valueOf(3)));
		List<AggBudgetMakeVO> update = new ArrayList<AggBudgetMakeVO>(), insert = new ArrayList<AggBudgetMakeVO>();
		for (AggBudgetMakeVO item : vos) {
			// 预算任务中编制流程为审核生效，流程状态单独处理
			String pk_budgettask = item.getParentVO().getPk_budgettask();
			Budgettask budgettask = NCLocator.getInstance().lookup(IBudgettaskService.class)
					.findBudgettaskByPk(pk_budgettask);
			if (!budgettask.getTaskprocess().equals(Integer.valueOf(TaskProcessEnum.ApproveSuccess.toIntValue()))) {
				item = (AggBudgetMakeVO) this.taskStateManager.taskStateProcess(item, "COMMIT", false, false);
			}

			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}
		List<AggBudgetMakeVO> ret = new ArrayList<AggBudgetMakeVO>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.insert(insert.toArray(new AggBudgetMakeVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.update(update.toArray(new AggBudgetMakeVO[0]))));
		}
		return ret.toArray(new AggBudgetMakeVO[0]);
	}

	public AggBudgetMakeVO[] callbackUNSAVE(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetMakeVO> update = new ArrayList<AggBudgetMakeVO>(), insert = new ArrayList<AggBudgetMakeVO>();
		for (AggBudgetMakeVO item : vos) {
			item = (AggBudgetMakeVO) this.taskStateManager.taskStateProcess(vos[0], "CALLBACK", false, true);
			// 状态是已汇总的编制单不允许收回或取消审批
			checkHassummary(item);
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}
		List<AggBudgetMakeVO> ret = new ArrayList<AggBudgetMakeVO>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.insert(insert.toArray(new AggBudgetMakeVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.update(update.toArray(new AggBudgetMakeVO[0]))));
		}
		return ret.toArray(new AggBudgetMakeVO[0]);
	}

	private void checkHassummary(AggBudgetMakeVO vo) throws BusinessException {
		if (Objects.nonNull(vo.getParentVO().getHassummary()) && vo.getParentVO().getHassummary().booleanValue()) {
			throw new BusinessException("已汇总单据不能取消审核或收回。");
		}
	}























	public AggBudgetMakeVO[] callbackAPPROVE(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetMakeVO> update = new ArrayList<AggBudgetMakeVO>(), insert = new ArrayList<AggBudgetMakeVO>();
		for (AggBudgetMakeVO item : vos) {

			if (item.getParentVO().getApprovestatus().equals(Integer.valueOf(-1))) {
				item = (AggBudgetMakeVO) this.taskStateManager.taskStateProcess(vos[0], "CALLBACK", false, false);
			} else if (!item.getParentVO().getApprovestatus().equals(Integer.valueOf(2))) {

				if (item.getParentVO().getApprovestatus().equals(Integer.valueOf(1))) {
					item = (AggBudgetMakeVO) this.taskStateManager.taskStateProcess(vos[0], "APPROVE", false, true);
				}
			}
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}
		List<AggBudgetMakeVO> ret = new ArrayList<AggBudgetMakeVO>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.insert(insert.toArray(new AggBudgetMakeVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.update(update.toArray(new AggBudgetMakeVO[0]))));
		}
		// modify by wy at 审批回写 四级采购项目预算状态 2024年12月20日
		CGFourWriteBakDataUtil.callbackApproveBudgetMakeAggVOs(vos);
		return ret.toArray(new AggBudgetMakeVO[0]);
	}

	public AggBudgetMakeVO[] callbackUNAPPROVE(AggBudgetMakeVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetMakeVO> update = new ArrayList<AggBudgetMakeVO>(), insert = new ArrayList<AggBudgetMakeVO>();
		for (AggBudgetMakeVO item : vos) {
			// 状态是已汇总的编制单不允许收回或取消审批
			checkHassummary(item);
			item = (AggBudgetMakeVO) this.taskStateManager.taskStateProcess(vos[0], "UNAPPROVE", false, true);
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}
		List<AggBudgetMakeVO> ret = new ArrayList<AggBudgetMakeVO>();

		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.insert(insert.toArray(new AggBudgetMakeVO[0]))));
		}


		if (update.size() > 0) {
			ret.addAll(Arrays.asList(this.dao.update(update.toArray(new AggBudgetMakeVO[0]))));
		}


		// modify by wy at 审批回写 四级采购项目预算状态 2024年12月20日
		CGFourWriteBakDataUtil.callbackUnApproveBudgetMakeAggVOs(vos);
		return ret.toArray(new AggBudgetMakeVO[0]);
	}
	public BillCodeContext getBillCodeContext(String coderuleid) throws BusinessException {
		return super.getBillCodeContext(coderuleid);
	}
	public BillCodeContext getBillCodeContext(String coderuleid, String pkgroup, String pkorg)
			throws BusinessException {
		return super.getBillCodeContext(coderuleid, pkgroup, pkorg);
	}
	public AggBudgetIndicatorVO queryAggBudgetIndicatorVO(String pk_org, String nyear, String pk_budgettype,
														  String pk_budgetdept) throws BusinessException {
		if (Objects.nonNull(nyear) && Objects.nonNull(pk_budgettype)) {
			String condition = "(pk_org = '" + pk_org + "' and nyear = '" + nyear + "' and pk_budgettype = '"
					+ pk_budgettype + "' and APPROVESTATUS =  1 )";
			IBudgetIndicatorVOService budgetIndicatorVOService = NCLocator.getInstance()
					.lookup(IBudgetIndicatorVOService.class);
			AggBudgetIndicatorVO[] aggBudgetIndicatorVOs = budgetIndicatorVOService
					.listAggBudgetIndicatorVOByCondition(condition);
			if (Objects.nonNull(aggBudgetIndicatorVOs)) {
				if (aggBudgetIndicatorVOs.length == 1) {
					BudgetIndicatorBVO[] bvos = (BudgetIndicatorBVO[]) aggBudgetIndicatorVOs[0].getAllChildrenVO();
					List<BudgetIndicatorBVO> listbvos = new ArrayList<BudgetIndicatorBVO>();
					for (BudgetIndicatorBVO bvo : bvos) {
						if (Objects.nonNull(pk_budgetdept) && bvo.getPk_budgetdept().equals(pk_budgetdept)) {
							listbvos.add(bvo);
						}
					}
					AggBudgetIndicatorVO newAgg = new AggBudgetIndicatorVO();
					newAgg.setParentVO(aggBudgetIndicatorVOs[0].getParentVO());
					newAgg.setChildrenVO(
							listbvos.toArray(new BudgetIndicatorBVO[0]));
					return newAgg;
				}
				if (aggBudgetIndicatorVOs.length > 1) {
					IBudgettypeService budgettypeService = NCLocator.getInstance()
							.lookup(IBudgettypeService.class);
					Budgettype budgettype = budgettypeService.findBudgettypeByPk(pk_budgettype, false);
					throw new BusinessException(nyear + "年度下，预算类型：" + budgettype.getName() + "，对应的支出指标下达单据数量不唯一，请检查！");
				}
			}
		}
		return null;
	}

	public AggBudgetMakeVO writeBackByReply(AggBudgetReplyVO billVo, Integer taskState) throws BusinessException {
		BudgetReplyDetailVO[] replyDetailVos = (BudgetReplyDetailVO[]) billVo.getChildren(BudgetReplyDetailVO.class);
		/*
		 * 取对应编制单据主键 如果存在二上编制单据则取二上编制单据主键，如果没有，则取一上编制单据主键
		 */
		SpBudgetReplyDetailVO[] spreplyDetailVos = (SpBudgetReplyDetailVO[]) billVo
				.getChildren(SpBudgetReplyDetailVO.class);
		String pk_budgetmake = StringUtils.isNotEmpty(billVo.getParentVO().getPk_secondupbill())
				? billVo.getParentVO().getPk_secondupbill()
				: billVo.getParentVO().getPk_firstupbill();
		AggBudgetMakeVO makeVo = findAggBudgetMakeVOByPk(pk_budgetmake);
		BudgetMakeDetailVO[] makeDetailVos = (BudgetMakeDetailVO[]) makeVo.getChildren(BudgetMakeDetailVO.class);
		Map<String, BudgetMakeDetailVO> makeDetailMap = new HashMap<String, BudgetMakeDetailVO>();
		for (BudgetMakeDetailVO vo : makeDetailVos) {
			makeDetailMap.put(vo.getIdcode(), vo);
		}
		// 回写数据至编制单
		BudgetMakeDetailVO tempMakeDetailVo = null;
		List<BudgetMakeDetailVO> tempMakeDetailVoList = new ArrayList<BudgetMakeDetailVO>();
		for (BudgetReplyDetailVO vo : replyDetailVos) {
			tempMakeDetailVo = makeDetailMap.get(vo.getIdcode());
			if (tempMakeDetailVo != null) { // 对应编制明细主键不为空
				tempMakeDetailVo.setStatus(1);
				if (billVo.getParentVO().getTaskstage().intValue() == 2) { // 一下批复：更新一下批复数
					tempMakeDetailVo.setAmount_firstdown(vo.getAmount_firstdown());
					tempMakeDetailVo.setDef3(vo.getDef3());
					if (taskState.equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {// 编制完成时 更新编制单和批复单的本年最终预算数
						vo.setAmount(vo.getAmount_firstdown());
						tempMakeDetailVo.setAmount(vo.getAmount_firstdown());
					}
				} else if (billVo.getParentVO().getTaskstage().intValue() == 4) {// 二下批复：更新二下批复数
					tempMakeDetailVo.setAmount_seconddown(vo.getAmount_seconddown());
					tempMakeDetailVo.setDef4(vo.getDef4());
					if (taskState.equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {// 编制完成时 更新编制单和批复单的本年最终预算数
						vo.setAmount(vo.getAmount_seconddown());
						tempMakeDetailVo.setAmount(vo.getAmount_seconddown());
					}
				}
				tempMakeDetailVoList.add(tempMakeDetailVo);
			} else {
				SequenceGenerator sequenceGenerator = new SequenceGenerator();
				String pkFirstDetail = sequenceGenerator.generate();
				tempMakeDetailVo = new BudgetMakeDetailVO();
				tempMakeDetailVo.setPk_budgetmakedetail(pkFirstDetail);
				tempMakeDetailVo.setStatus(2);
				VOEntityUtil.copyVOByVO(tempMakeDetailVo, BudgetReplyDetailVO.COPY_KEYS, vo,
						BudgetReplyDetailVO.COPY_KEYS);
				vo.setPk_firstupdetail(pkFirstDetail);
				this.dao.update(vo);
				if (taskState.equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {
					if (vo.getAmount_seconddown() != null) {
						// 先把这个加上，否则预算编制的保存报错
						tempMakeDetailVo.setAmount(vo.getAmount_seconddown());
					} else {
						// 先把这个加上，否则预算编制的保存报错
						tempMakeDetailVo.setAmount(vo.getAmount_firstdown());
					}
				}
				tempMakeDetailVoList.add(tempMakeDetailVo);
			}
			//把“一下批复说明”回写到一上编制单表体对应预算编制明细表体行“一下批复说明“上
			if (billVo.getParentVO().getTaskstage() == 2) {
				tempMakeDetailVo.setFirstdown_memo(vo.getFirstdown_memo());
			}
			tempMakeDetailVo.setSeconddown_memo(vo.getSeconddown_memo());
		}
		// 添加专项子表
		SpBudgetMakeDetailVO[] spmakeDetailVos = (SpBudgetMakeDetailVO[]) makeVo
				.getChildren(SpBudgetMakeDetailVO.class);
		if(spmakeDetailVos != null && spreplyDetailVos != null) {
			Map<String, SpBudgetMakeDetailVO> spmakeDetailMap = new HashMap<String, SpBudgetMakeDetailVO>();
			for (SpBudgetMakeDetailVO vo : spmakeDetailVos) {
				spmakeDetailMap.put(vo.getDef1(), vo);
			}

			SpBudgetMakeDetailVO sptempMakeDetailVo = null;
			List<SpBudgetMakeDetailVO> sptempMakeDetailVoList = new ArrayList<SpBudgetMakeDetailVO>();
			for (SpBudgetReplyDetailVO vo : spreplyDetailVos) {

				sptempMakeDetailVo = spmakeDetailMap.get(vo.getDef1());

				if (sptempMakeDetailVo != null) {

					sptempMakeDetailVo.setStatus(1);

					if (billVo.getParentVO().getTaskstage().intValue() == 2) {
						sptempMakeDetailVo.setAmount_firstdown(vo.getAmount_firstdown());
						if (taskState.equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {
							vo.setAmount(vo.getAmount_firstdown());
							sptempMakeDetailVo.setAmount(vo.getAmount_firstdown());
						}
					} else if (billVo.getParentVO().getTaskstage().intValue() == 4) {
						sptempMakeDetailVo.setAmount_seconddown(vo.getAmount_seconddown());
						if (taskState.equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {
							vo.setAmount(vo.getAmount_seconddown());
							sptempMakeDetailVo.setAmount(vo.getAmount_seconddown());
						}
					}

					sptempMakeDetailVoList.add(sptempMakeDetailVo);
				} else {

					SequenceGenerator sequenceGenerator = new SequenceGenerator();
					String pkFirstDetail = sequenceGenerator.generate();
					sptempMakeDetailVo = new SpBudgetMakeDetailVO();
					sptempMakeDetailVo.setPk_spbudgetmakedetail(pkFirstDetail);
					sptempMakeDetailVo.setStatus(2);
					VOEntityUtil.copyVOByVO(sptempMakeDetailVo, SpBudgetReplyDetailVO.COPY_KEYS, vo,
							SpBudgetReplyDetailVO.COPY_KEYS);

					vo.setPk_firstupdetail(pkFirstDetail);
					this.dao.update(vo);
					if (taskState.equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {
						if (vo.getAmount_seconddown() != null) {

							sptempMakeDetailVo.setAmount(vo.getAmount_seconddown());
						} else {

							sptempMakeDetailVo.setAmount(vo.getAmount_firstdown());
						}
					}

					sptempMakeDetailVoList.add(sptempMakeDetailVo);
				}
			}
			makeVo.setChildren(SpBudgetMakeDetailVO.class,
					sptempMakeDetailVoList.toArray(new SpBudgetMakeDetailVO[0]));
		}
		//ZQ TODO 2024/2/29  需要处理逻辑删除下的回写逻辑
		//回写政府采购页签
		GovpurchVO[] govpurchVOS = (GovpurchVO[]) makeVo.getChildren(GovpurchVO.class);
		GovpurchReplyVO[] govpurchReplyVOS = (GovpurchReplyVO[]) billVo.getChildren(GovpurchReplyVO.class);
		List<GovpurchVO> newGov = new ArrayList<GovpurchVO>();
		if (Objects.nonNull(govpurchVOS)) {
			for (GovpurchVO gov : govpurchVOS) {
				gov.setStatus(3);
				newGov.add(gov);
			}
		}
		if (Objects.nonNull(govpurchReplyVOS)) {
			for (GovpurchReplyVO govrep : govpurchReplyVOS) {
				GovpurchVO govpurchVO = new GovpurchVO();
				VOEntityUtil.copyVOByVO(govpurchVO, GovpurchVO.COPY_KEYS, govrep, GovpurchVO.COPY_KEYS);
				govpurchVO.setStatus(2);
				newGov.add(govpurchVO);
			}
		}
		if (Objects.nonNull(govpurchVOS) || Objects.nonNull(govpurchReplyVOS)) {
			makeVo.setChildren(GovpurchVO.class, newGov.toArray(new GovpurchVO[0]));
		}

		//回写资产分配页签
		AssetAllocationVO[] assetAllocationVOS = (AssetAllocationVO[]) makeVo.getChildren(AssetAllocationVO.class);
		AssetAllocationReplyVO[] assetAllocationReplyVOS = (AssetAllocationReplyVO[]) billVo
				.getChildren(AssetAllocationReplyVO.class);
		List<AssetAllocationVO> newAsset = new ArrayList<AssetAllocationVO>();
		if (Objects.nonNull(assetAllocationVOS)) {
			for (AssetAllocationVO ass : assetAllocationVOS) {
				ass.setStatus(3);
				newAsset.add(ass);
			}
		}
		if (Objects.nonNull(assetAllocationReplyVOS)) {
			for (AssetAllocationReplyVO assreply : assetAllocationReplyVOS) {
				AssetAllocationVO assetall = new AssetAllocationVO();
				VOEntityUtil.copyVOByVO(assetall, AssetAllocationVO.COPY_KEYS, assreply, AssetAllocationVO.COPY_KEYS);
				assetall.setStatus(2);
				newAsset.add(assetall);
			}
		}
		if (Objects.nonNull(assetAllocationVOS) || Objects.nonNull(assetAllocationReplyVOS)) {
			makeVo.setChildren(AssetAllocationVO.class, newAsset.toArray(new AssetAllocationVO[0]));
		}

		if (taskState != null && taskState.equals(Integer.valueOf(TaskStateEnum.Complete.toIntValue()))) {
			// 审批完成后上报单状态改为编报完成
			makeVo.getParentVO().setStatus(1);
			makeVo.getParentVO().setTaskstate(Integer.valueOf(TaskStateEnum.Complete.toIntValue()));
		}

		makeVo.setChildren(BudgetMakeDetailVO.class,
				tempMakeDetailVoList.toArray(new BudgetMakeDetailVO[0]));
		//回写表头 批复合计金额
		makeVo.getParentVO().setReplytotal(billVo.getParentVO().getReplytotal());

		reWriteMemo(billVo);
		// 更新编制单据
		saveAggBudgetMakeVO(makeVo);

		return findAggBudgetMakeVOByPk(pk_budgetmake);
	}

	/**
	 * 回写批复单对应的所有编制单 批复说明 字段
	 * 一上一下流程的编制单和二上二下流程中二上的编制单的数据已经在 writeBackByReply 方法中完成回写
	 * 只有二上二下流程中的一上没有被回写
	 * @param replyVO
	 * @throws BusinessException
	 */
	private void reWriteMemo(AggBudgetReplyVO replyVO) throws BusinessException {
		BudgetReplyVO replyParentVO = replyVO.getParentVO();
		if(StringUtils.isEmpty(replyParentVO.getPk_secondupbill())){
			return;
		}
		String pk_firstupbill = replyParentVO.getPk_firstupbill();
		BudgetReplyDetailVO[] replyDetailVOS = (BudgetReplyDetailVO[]) replyVO.getChildren(BudgetReplyDetailVO.class);
		AggBudgetMakeVO[] makeVOS = this.listAggBudgetMakeVOByPk(pk_firstupbill);
		if(null != makeVOS && makeVOS.length > 0){
			BudgetMakeDetailVO[] makeDetailVOS = (BudgetMakeDetailVO[]) makeVOS[0].getChildren(BudgetMakeDetailVO.class);
			Map<String, BudgetMakeDetailVO> makeDetailMap = new HashMap<String, BudgetMakeDetailVO>();
			for (BudgetMakeDetailVO vo : makeDetailVOS) {
				makeDetailMap.put(vo.getIdcode(), vo);
			}

			for (BudgetReplyDetailVO replyDetailVO : replyDetailVOS) {
				if(makeDetailMap.containsKey(replyDetailVO.getIdcode())){
					BudgetMakeDetailVO makeDetailVO = makeDetailMap.get(replyDetailVO.getIdcode());
					makeDetailVO.setFirstdown_memo(replyDetailVO.getFirstdown_memo());
					makeDetailVO.setSeconddown_memo(replyDetailVO.getSeconddown_memo());
				}
			}
			this.saveAggBudgetMakeVO(makeVOS);
		}

	}

	/**
	 * 根据编制状态，设置编制阶段，以及需要关联的pk
	 */
	private void setTaskage(BudgetMakeVO makeVO, AggBudgetReplyVO vo) {
		makeVO.setApprovedate(null);
		makeVO.setApprovenote(null);
		makeVO.setApprover(null);
		makeVO.setModifier(null);
		makeVO.setModifiedtime(null);
		makeVO.setLastmaketime(null);
		makeVO.setPk_firstdownbill(vo.getParentVO().getPk_budgetreply());
		makeVO.setTaskstage(Integer.valueOf(TaskStageEnum.SecondUp.toIntValue()));
		makeVO.setTaskstate(Integer.valueOf(TaskStateEnum.SecondUpMake.toIntValue()));// 任务状态 二上编制
		makeVO.setApprovestatus(Integer.valueOf(-1));
	}

	public void createSecondMakeBill(AggBudgetReplyVO billVo) throws BusinessException {
		AggBudgetMakeVO aggmakeVO = new AggBudgetMakeVO();
		BudgetMakeVO newmakeVO = new BudgetMakeVO();
		VOEntityUtil.copyVOByVO(newmakeVO, BudgetReplyVO.COPY_KEYS, billVo.getParentVO(), BudgetReplyVO.COPY_KEYS);
		setTaskage(newmakeVO, billVo);
		IBudgetReplyVOService budgetReplyVOService = NCLocator.getInstance()
				.lookup(IBudgetReplyVOService.class);
		AggBudgetReplyVO vo2 = budgetReplyVOService.findAggBudgetReplyVOByPk(billVo.getParentVO().getPk_budgetreply());
		//批复单明细
		BudgetReplyDetailVO[] replyDetailVOs = (BudgetReplyDetailVO[]) vo2.getChildren(BudgetReplyDetailVO.class);
		BudgetMakeDetailVO[] newmakeDetailVOs = new BudgetMakeDetailVO[replyDetailVOs.length];
		for (int i = 0; i < newmakeDetailVOs.length; i++) {
			newmakeDetailVOs[i] = new BudgetMakeDetailVO();
		}
		VOEntityUtil.copyVOsByVOs(newmakeDetailVOs, BudgetReplyDetailVO.COPY_KEYS, replyDetailVOs,
				BudgetReplyDetailVO.COPY_KEYS);
		for (int i = 0; i < newmakeDetailVOs.length; i++) {
			newmakeDetailVOs[i].setStatus(2);
			newmakeDetailVOs[i].setPk_firstupdetail(replyDetailVOs[i].getPk_firstupdetail());
			newmakeDetailVOs[i].setPk_firstdowndetail(replyDetailVOs[i].getPk_budgetreplydetail());
			newmakeDetailVOs[i].setAmount_secondup(replyDetailVOs[i].getAmount_firstdown());
			//把“一下批复说明”带到二上编制单预算编制明细表体行“一下批复说明“上
			newmakeDetailVOs[i].setFirstdown_memo(replyDetailVOs[i].getFirstdown_memo());
		}
		//政府采购预算
		GovpurchReplyVO[] govpurchReplyVOS = (GovpurchReplyVO[]) vo2.getChildren(GovpurchReplyVO.class);
		if (Objects.nonNull(govpurchReplyVOS) && govpurchReplyVOS.length > 0) {
			GovpurchVO[] govpurchVOS = new GovpurchVO[govpurchReplyVOS.length];
			for (int i = 0; i < govpurchVOS.length; i++) {
				govpurchVOS[i] = new GovpurchVO();
			}
			VOEntityUtil.copyVOsByVOs(govpurchVOS, GovpurchReplyVO.COPY_KEYS, govpurchReplyVOS,
					GovpurchReplyVO.COPY_KEYS);
			for (int i = 0; i < govpurchVOS.length; i++) {
				govpurchVOS[i].setStatus(2);
				govpurchVOS[i].setPk_govpurch(null);
			}
			aggmakeVO.setChildren(GovpurchVO.class, govpurchVOS);
		}
		//资产配置预算
		AssetAllocationReplyVO[] assetAllocationReplyVOS = (AssetAllocationReplyVO[]) vo2
				.getChildren(AssetAllocationReplyVO.class);
		if (Objects.nonNull(assetAllocationReplyVOS) && assetAllocationReplyVOS.length > 0) {
			AssetAllocationVO[] assetAllocationVOS = new AssetAllocationVO[assetAllocationReplyVOS.length];
			for (int i = 0; i < assetAllocationVOS.length; i++) {
				assetAllocationVOS[i] = new AssetAllocationVO();
			}
			VOEntityUtil.copyVOsByVOs(assetAllocationVOS, AssetAllocationReplyVO.COPY_KEYS, assetAllocationReplyVOS,
					AssetAllocationReplyVO.COPY_KEYS);

			for (int i = 0; i < assetAllocationVOS.length; i++) {
				assetAllocationVOS[i].setStatus(2);
				assetAllocationVOS[i].setPk_assetallaction(null);
			}
			aggmakeVO.setChildren(AssetAllocationVO.class, assetAllocationVOS);
		}
		newmakeVO.setHassummary(new UFBoolean(false));
		aggmakeVO.setParentVO(newmakeVO);
		aggmakeVO.setChildren(BudgetMakeDetailVO.class, newmakeDetailVOs);
		getMainVO(aggmakeVO).setStatus(2);
		//一下批复生成二上编制单时，把一上编制单的制单人及创建人带到二上编制单中
		initDefaultData(aggmakeVO.getParentVO());
		initTransTypeData(aggmakeVO.getParentVO());
		// 计算idcode
		GetIdCode.getIdCode((CircularlyAccessibleValueObject[]) aggmakeVO.getChildren(BudgetMakeDetailVO.class));
		saveAggBudgetMakeVO(aggmakeVO);
	}

	/**
	 * 根据批复单的交易类型，确定编制单的交易类型
	 *
	 * @throws BusinessException
	 */
	private void initTransTypeData(BudgetMakeVO vo) throws BusinessException {
		String makeTransTypeCode = vo.getTranstype();
		makeTransTypeCode = makeTransTypeCode.substring(makeTransTypeCode.indexOf("-"));
		makeTransTypeCode = vo.getBilltype() + makeTransTypeCode;
		vo.setTranstype(makeTransTypeCode);
		BilltypeVO billtypeVO = BillTypeQueryTools.queryBillTypeById(makeTransTypeCode);
		if (Objects.isNull(billtypeVO)) {
			throw new BusinessException("没有对应的交易类型:" + makeTransTypeCode);
		}
		vo.setTranstypepk(billtypeVO.getPk_billtypeid());
	}

	@Override
	public AggBudgetMakeVO CallBackProcess(String upPk) throws BusinessException {
		BaseDAO daosql = new BaseDAO();
		String cleansql = "";
		String delsql = "PK_BUDGETMAKE = '" + upPk + "'";
		AggBudgetMakeVO[] vos = listAggBudgetMakeVOByCondition(delsql);
		// 取消审批后根据是否编报完成和阶段，修改编报完成状态为一上上报或二上上报
		String findState = "PK_BUDGETMAKE = '" + upPk + "' and TASKSTATE ='" + TaskStateEnum.Complete.toIntValue()
				+ "'";
		AggBudgetMakeVO[] comVo = listAggBudgetMakeVOByCondition(findState);
		if (comVo.length > 0) {
			String updateSql = "";
			if (vos[0].getParentVO().getTaskstage().intValue() == 1) {
				updateSql = "update hrpbm_budgetmake set TASKSTATE = '" + TaskStateEnum.FirstUpReport.toIntValue()
						+ "' where PK_BUDGETMAKE = '" + upPk + "'";
			}
			if (vos[0].getParentVO().getTaskstage().intValue() == 3) {
				updateSql = "update hrpbm_budgetmake set TASKSTATE = '" + TaskStateEnum.SecondUpReport.toIntValue()
						+ "' where PK_BUDGETMAKE = '" + upPk + "'";
			}
			daosql.executeUpdate(updateSql);
		}

		CircularlyAccessibleValueObject[] bvos = vos[0].getChildrenVO();
		List<CircularlyAccessibleValueObject> needDel = new ArrayList<CircularlyAccessibleValueObject>();
		for (CircularlyAccessibleValueObject bvo : bvos) {
			if (vos[0].getParentVO().getTaskstage().intValue() == 1) {// 处理一上 上报单
				// 清空所有批复数
				cleansql = "update hrpbm_budgetmakedetail set amount_firstdown=null,amount=null,def3=null  where PK_BUDGETMAKE = '"
						+ upPk + "'";

				if (bvo.getAttributeValue("amount_firstup") == null) {
					needDel.add(bvo);
				}
				daosql.executeUpdate(cleansql);
			}
			if (vos[0].getParentVO().getTaskstage().intValue() == 3) {// 处理二上 上报单
				// 清空所有批复数
				cleansql = "update hrpbm_budgetmakedetail set amount_seconddown=null,amount=null,def4=null  where PK_BUDGETMAKE = '"
						+ upPk + "'";
				if (bvo.getAttributeValue("amount_secondup") == null) {
					needDel.add(bvo);
				}
				daosql.executeUpdate(cleansql);
			}
		}

		daosql.deleteVOList(needDel);
		vos = this.listAggBudgetMakeVOByCondition(delsql);
		//  重新计算表头 批复合计金额  政府采购预算合计金额 资产配置预算合计金额
		calculateMoneyTotal(vos[0]);
		//  取消审核把编制单上一下批复说明和二下批复说明清空。
		replyMemoProcess(vos[0]);
		dao.update(vos[0]);
		return vos[0];
	}

	/**
	 * 取消审核把编制单上一下批复说明和二下批复说明清空。
	 * @param vo
	 * @throws BusinessException
	 */
	private void replyMemoProcess(AggBudgetMakeVO vo) throws BusinessException {
		BudgetMakeVO parentVO = vo.getParentVO();
		BudgetMakeDetailVO[] makeDetailVOS = (BudgetMakeDetailVO[]) vo.getChildren(BudgetMakeDetailVO.class);
		if (parentVO.getTaskstate() == TaskStateEnum.FirstUpReport.toIntValue()){
			//一下时，清空一下批复说明
			for (BudgetMakeDetailVO replyDetailVO : makeDetailVOS) {
				replyDetailVO.setFirstdown_memo(null);
				replyDetailVO.setStatus(VOStatus.UPDATED);
			}
		}else{
			//二下时，清空二下批复说明
			for (BudgetMakeDetailVO replyDetailVO : makeDetailVOS) {
				replyDetailVO.setSeconddown_memo(null);
				replyDetailVO.setStatus(VOStatus.UPDATED);
			}
		}
	}

	/**
	 * 重新计算表头
	 * 批复合计金额
	 * 政府采购预算合计金额 资产配置预算合计金额 由保存后计算，此处不计算
	 * @param vo
	 * @throws BusinessException
	 */
	private void calculateMoneyTotal(AggBudgetMakeVO vo) throws BusinessException {
		BudgetMakeVO parentVO = vo.getParentVO();
		if (parentVO.getTaskstate() == TaskStateEnum.FirstUpReport.toIntValue()){
			//一下时，清空批复合计金额
			parentVO.setReplytotal(UFDouble.ZERO_DBL);
		}else{
			//二下时，修改批复合计金额为一下批复合计金额
			String pk_budgetReply = parentVO.getPk_firstdownbill();
			IBudgetReplyVOService budgetReplyVOService = NCLocator.getInstance().lookup(IBudgetReplyVOService.class);
			AggBudgetReplyVO[] aggBudgetReplyVOS = budgetReplyVOService.listAggBudgetReplyVOByPk(pk_budgetReply);
			if(null != aggBudgetReplyVOS && aggBudgetReplyVOS.length > 0){
				parentVO.setReplytotal(aggBudgetReplyVOS[0].getParentVO().getReplytotal());
			}
		}
	}


	@Override
	public Map<String, Object> checkBudgetDimDetail(AggBudgetMakeVO... vos) throws BusinessException {
		Map<String, Object> externalData = new HashMap<String, Object>();
		// 同步表体维度
		SetChildColumnValue.setChildColumnValue(vos, true);
		GettotalMny(vos);
		for (AggBudgetMakeVO vo : vos) {
			// 计算idcode
			GetIdCode.getIdCode((CircularlyAccessibleValueObject[]) vo.getChildren(BudgetMakeDetailVO.class));
			// 指标下达的校验
			// 根据nyear、pk_budgettype查询指标下达的单据数据
			AggBudgetIndicatorVO aggBudgetIndicatorVO = queryAggBudgetIndicatorVO(vo.getParentVO().getPk_org(),
					vo.getParentVO().getNyear(), vo.getParentVO().getPk_budgettype(),
					vo.getParentVO().getPk_budgetdept());
			if (Objects.isNull(aggBudgetIndicatorVO) || aggBudgetIndicatorVO.getAllChildrenVO().length == 0) {
				return null;
			}
			String queryMakeVoWherePart = "( vhashcode = 'CD' and  pk_org = '" + vo.getParentVO().getPk_org()
					+ "' and nyear = '" + vo.getParentVO().getNyear() + "' and pk_budgettype = '"
					+ vo.getParentVO().getTranstype().split("-")[3] + "' and pk_budgetdept = '"
					+ vo.getParentVO().getPk_budgetdept() + "' and pk_budgetmake != '"
					+ vo.getParentVO().getPk_budgetmake() + "')";
			String queryhisMakeVo = "select sum(COALESCE(amount_firstup,0)) amount_firstup," +
					"sum(COALESCE(amount_secondup,0)) amount_secondup," +
					"sum(COALESCE(amount_firstdown,0)) amount_firstdown," +
					"sum(COALESCE(amount_secondup,0)) amount_secondup,idcode from hrpbm_budgetmakedetail where" +
					queryMakeVoWherePart +
					" group by idcode";
			List<Map> budgetMakeDetailVOs = (List) this.dao.getBaseDAO().executeQuery(queryhisMakeVo,
					new MapListProcessor());
			StringBuffer str = new StringBuffer();
			// vos里面的下达金额，跟hisvos和vos里面的一上预算数或二上预算数的和进行比较，根据控制方式，进行控制。
			if (aggBudgetIndicatorVO.getParentVO().getIndicatordim().equals(IndicatorDimEnum.dept.value())) {
				if (vo.getParentVO().getTaskstage().equals(Integer.valueOf(TaskStageEnum.FirstUp.toIntValue()))) {// 一上阶段，用一上预算数和下达金额比较
					UFDouble totalfirst = vo.getParentVO().getTotalamount();
					if (Objects.nonNull(budgetMakeDetailVOs) && budgetMakeDetailVOs.size() > 0) {
						for (Map budgetMakeDetail : budgetMakeDetailVOs) {
							totalfirst = (new UFDouble(budgetMakeDetail.get("amount_firstup").toString()))
									.add(totalfirst);
						}
					}
					if (Objects.nonNull(vo.getParentVO().getIndicatoramount())) {
						validateamount(vo, totalfirst, str);
					}
				} else if (vo.getParentVO().getTaskstage()
						.equals(Integer.valueOf(TaskStageEnum.SecondUp.toIntValue()))) {// 二上阶段，用二上预算数和厦大金额比较
					UFDouble totalfirst = vo.getParentVO().getIndicatoramount();
					if (Objects.nonNull(budgetMakeDetailVOs) && budgetMakeDetailVOs.size() > 0) {
						for (Map budgetMakeDetail : budgetMakeDetailVOs) {
							totalfirst = (new UFDouble(budgetMakeDetail.get("amount_secondup").toString()))
									.add(totalfirst);
						}
					}
					if (Objects.nonNull(vo.getParentVO().getIndicatoramount())) {
						validateamount(vo, totalfirst, str);
					}
				}else if (vo.getParentVO().getTaskstage().equals(TaskStageEnum.ApproveSuccess.toIntValue())) {// 审核生效，用二下
					UFDouble totalfirst = vo.getParentVO().getTotalamount();
					if (Objects.nonNull(budgetMakeDetailVOs) && budgetMakeDetailVOs.size() > 0) {
						for (Map budgetMakeDetail : budgetMakeDetailVOs) {
							totalfirst = new UFDouble(budgetMakeDetail.get("amount_seconddown").toString())
									.add(totalfirst);
						}
					}
					if (Objects.nonNull(vo.getParentVO().getIndicatoramount())) {
						this.validateamount(vo, totalfirst, str);
					}
				}
			} else if (aggBudgetIndicatorVO.getParentVO().getIndicatordim().equals(IndicatorDimEnum.schema.value())) {
				BudgetMakeDetailVO[] currentDetailVOs = (BudgetMakeDetailVO[]) vo.getChildren(BudgetMakeDetailVO.class);
				for (BudgetMakeDetailVO currentDetailVO : currentDetailVOs) {
					UFDouble totalamount = UFDouble.ZERO_DBL;
					if (vo.getParentVO().getTaskstage().equals(Integer.valueOf(TaskStageEnum.FirstUp.toIntValue()))) {
						totalamount = currentDetailVO.getAmount_firstup();
					}
					if (vo.getParentVO().getTaskstage().equals(Integer.valueOf(TaskStageEnum.SecondUp.toIntValue()))) {
						totalamount = currentDetailVO.getAmount_secondup();
					}
					if (vo.getParentVO().getTaskstage().equals(TaskStageEnum.ApproveSuccess.toIntValue())) {
						totalamount = currentDetailVO.getAmount_seconddown();
					}

					for (Map detailMap : budgetMakeDetailVOs) {
						if (detailMap.get("idcode").equals(currentDetailVO.getIdcode())) {
							if (vo.getParentVO().getTaskstage()
									.equals(Integer.valueOf(TaskStageEnum.FirstUp.toIntValue()))) {
								totalamount = totalamount.add(new UFDouble(detailMap.get("amount_firstup").toString()));
							}
							if (vo.getParentVO().getTaskstage()
									.equals(Integer.valueOf(TaskStageEnum.SecondUp.toIntValue()))) {
								totalamount = totalamount
										.add(new UFDouble(detailMap.get("amount_secondup").toString()));
							}
							if (vo.getParentVO().getTaskstage().equals(TaskStageEnum.ApproveSuccess.toIntValue())) {
								totalamount = totalamount
										.add(new UFDouble(detailMap.get("amount_seconddown").toString()));
							}
						}
					}
					if (Objects.nonNull(currentDetailVO.getIndicatoramount())) {
						if (vo.getParentVO().getTranstype().indexOf("YS01") > 0) {
							if (totalamount.compareTo(currentDetailVO.getIndicatoramount()) < 0) {
								String idcodeToStr = getStrByDimNonNull(currentDetailVO);
								str.append(
										idcodeToStr + "金额应大于等于dept下达金额" + currentDetailVO.getIndicatoramount() + "元。\n");
							}
						} else if (totalamount.compareTo(currentDetailVO.getIndicatoramount()) > 0) {
							String idcodeToStr = getStrByDimNonNull(currentDetailVO);
							str.append(idcodeToStr + "金额已超过dept下达金额" + currentDetailVO.getIndicatoramount() + "元。\n");
						}
					}
				}
			}
			// 提醒
			if (str.length() > 0) {
				if (aggBudgetIndicatorVO.getParentVO().getControltype()
						.equals(Integer.valueOf(BmBmindicatorCtrlTypeEnum.CTRL.toIntValue()))) {
					throw new BusinessException(str.toString());
				}
				if (aggBudgetIndicatorVO.getParentVO().getControltype()
						.equals(Integer.valueOf(BmBmindicatorCtrlTypeEnum.REMIND.toIntValue()))) {
					externalData.put("controltype", aggBudgetIndicatorVO.getParentVO().getControltype());
					externalData.put("message", str.toString());
				}
			}
		}
		return externalData;
	}
	private void validateamount(AggBudgetMakeVO vo, UFDouble totalamount, StringBuffer str) {
		if (vo.getParentVO().getTranstype().indexOf("YS01") > 0) {
			if (totalamount.compareTo(vo.getParentVO().getIndicatoramount()) < 0) {
				str.append("编制金额应大于等于dept下达金额" + vo.getParentVO().getIndicatoramount() + "元。\n");
			}
		} else if (totalamount.compareTo(vo.getParentVO().getIndicatoramount()) > 0) {
			str.append("编制金额已超过dept下达金额" + vo.getParentVO().getIndicatoramount() + "元。\n");
		}
	}

	/**
	 * 取消汇总
	 *
	 * @throws BusinessException
	 */
	@Override
	public void cancelDeptReport(ISuperVO... superVO) throws BusinessException {
		if (Objects.nonNull(superVO) && superVO.length > 0) {
			for (ISuperVO vo : superVO) {
				vo.setAttributeValue("pk_summarybill", null);
				vo.setAttributeValue("hassummary", "N");
			}
			this.dao.update(superVO);
		}
	}

//	public AggBudgetMakeVO queryYSDataForMake(AggBudgetMakeVO vo, String topcode) throws DAOException {
//		String sql = "select sum(AMOUNT) PLANMONEY,PK_INOUTCLASS pk_inoutbusiclass from HRPBM_BUDGETMAKEDETAIL where PK_BUDGETMAKE in (select PK_BUDGETMAKE from HRPBM_BUDGETMAKE where pk_org = '"
//				+ vo.getParentVO().getPk_org() + "' and NYEAR = '" + vo.getParentVO().getNyear()
//				+ "' and TASKSTATE = '99' and TRANSTYPE like '%CD-" + topcode + "') group by PK_INOUTCLASS";
//		List<ReportfundsSlaveVO> list = (List) this.dao.getBaseDAO().executeQuery(sql,
//				new BeanListProcessor(ReportfundsSlaveVO.class));
//		List<BudgetMakeDetailVO> newMakeDetailBodys = new ArrayList<BudgetMakeDetailVO>();
//		BudgetMakeDetailVO[] detailVOS = (BudgetMakeDetailVO[]) vo.getChildren(BudgetMakeDetailVO.class);
//		if (detailVOS.length > 0) {
//			for (BudgetMakeDetailVO detailVO : detailVOS) {
//				if (Objects.nonNull(list) && list.size() > 0) {
//					for (ReportfundsSlaveVO fundvo : list) {
////						if (Objects.equals(detailVO.getPk_inoutclass(), fundvo.getPk_inoutbusiclass())) {
//						// modify by wy at 适配930 2024年10月28日
//						if (Objects.equals(detailVO.getPk_inoutclass(), fundvo.getPk_inoutclass())) {
//							detailVO.setAmount_seconddown(fundvo.getPlanmoney());
//							break;
//						}
//						detailVO.setAmount_seconddown(new UFDouble(BigDecimal.ZERO));
//					}
//				} else {
//					detailVO.setAmount_seconddown(new UFDouble(BigDecimal.ZERO));
//				}
//				if (detailVO.getStatus() != 3) {
//					if (StringUtils.isEmpty(detailVO.getPk_budgetmakedetail())) {
//						detailVO.setStatus(2);
//					} else {
//						detailVO.setStatus(1);
//					}
//				} else {
//					detailVO.setStatus(3);
//				}
//				newMakeDetailBodys.add(detailVO);
//			}
//		} else if (Objects.nonNull(list) && list.size() > 0) {
//			for (ReportfundsSlaveVO fundvo : list) {
//				BudgetMakeDetailVO newdetailVo = new BudgetMakeDetailVO();
	////				newdetailVo.setPk_inoutclass(fundvo.getPk_inoutbusiclass());
//				// modify by wy at 适配930 2024年10月28日
//				newdetailVo.setPk_inoutclass(fundvo.getPk_inoutclass());
//				newdetailVo.setAmount_seconddown(fundvo.getPlanmoney());
//				newdetailVo.setStatus(2);
//				newMakeDetailBodys.add(newdetailVo);
//			}
//		}
//		vo.setChildrenVO((CircularlyAccessibleValueObject[]) newMakeDetailBodys.toArray(new BudgetMakeDetailVO[0]));
//		return vo;
//	}

	@Override
	public AggBudgetMakeVO queryYSDataForMake(AggBudgetMakeVO vo, String topcode) throws BusinessException {
		BudgetMakeVO parentVO = vo.getParentVO();
		BudgetMakeDetailVO[] detailVOS = (BudgetMakeDetailVO[]) vo.getChildren(BudgetMakeDetailVO.class);
		IBudgettypeService budgettypeService = NCLocator.getInstance().lookup(IBudgettypeService.class);
		String[] budgetTypePks = budgettypeService.listBudgettypePkByCond("code = '" + topcode + "' ");

		List<String> activeBudgetDim = BudgetCalUtil.getActiveBudgetDim(budgetTypePks[0],
				parentVO.getNyear());


		List<String> topcodeDim = BudgetCalUtil.getActiveBudgetDim(budgetTypePks[0],
				parentVO.getNyear());

		if(!new HashSet<>(topcodeDim).containsAll(activeBudgetDim)){
			throw new BusinessException("汇总维度匹配不到数据。");
		}


		// 按年度+审核通过
		String sql = " select pk_inoutclass,pk_project,pk_fundsource,pk_operation,pk_budgetdept,defdim1,defdim2, " +
				" defdim3,defdim4,defdim5,defdim6,defdim7,defdim8,defdim9,defdim10,nyear,sum(amount) amount_seconddown " +
				" from hrpbm_budgetmakedetail" +
				" where pk_budgetmake in (select pk_budgetmake from hrpbm_budgetmake where pk_org = '" +
				vo.getParentVO().getPk_org() + "' and nyear = '" + vo.getParentVO().getNyear() +
				"' and taskstate = '99' and transtype like '%CD-" + topcode +
				"') group by pk_inoutclass,pk_project,pk_fundsource,pk_operation,pk_budgetdept,defdim1,defdim2, " +
				" defdim3,defdim4,defdim5,defdim6,defdim7,defdim8,defdim9,defdim10,nyear ";

		List<BudgetMakeDetailVO> dataList = (List<BudgetMakeDetailVO>) dao.getBaseDAO().executeQuery(sql,
				new BeanListProcessor(BudgetMakeDetailVO.class));
		if(Objects.isNull(dataList) || dataList.isEmpty()){
			throw new BusinessException("汇总维度匹配不到数据。");
		}

		Map<String,BudgetMakeDetailVO> dimensionalGroupingMap = new HashMap<>();

		//相同维度合并
		Iterator<BudgetMakeDetailVO> iterator = dataList.iterator();
		while (iterator.hasNext()) {
			BudgetMakeDetailVO item = iterator.next();
			StringBuilder key = new StringBuilder();
			for (String field : activeBudgetDim) {
				key.append(item.getAttributeValue(field));
			}
			if(dimensionalGroupingMap.containsKey(key.toString())){
				BudgetMakeDetailVO makeDetailVO = dimensionalGroupingMap.get(key.toString());
				makeDetailVO.setAmount_seconddown(makeDetailVO.getAmount_seconddown().add(item.getAmount_seconddown()));
				iterator.remove();
			}else{
				dimensionalGroupingMap.put(key.toString(),item);
			}
		}
		List<BudgetMakeDetailVO> newMakeDetailBodys = new ArrayList<>();
		// 是否存在匹配数据
		boolean isMatch = false;
		//未匹配到的数据
		List<BudgetMakeDetailVO> nonMatchingList = new ArrayList();
		nonMatchingList.addAll(dataList);
		for (BudgetMakeDetailVO detailVO : detailVOS) {
			if(detailVO.getStatus() == VOStatus.DELETED){
				newMakeDetailBodys.add(detailVO);
				continue;
			}
			// 初始化默认值
			UFDouble amountSecondDown = detailVO.getAmount_seconddown();
			int newStatus = VOStatus.UNCHANGED;

			iterator = dataList.iterator();
			while (iterator.hasNext()) {
				BudgetMakeDetailVO targetVo = iterator.next();
				StringBuilder sourceKey = new StringBuilder();
				StringBuilder targetKey = new StringBuilder();
				for (String field : activeBudgetDim) {
					if(field.equals("pk_budgetdept")){
						continue;
					}
					sourceKey.append(detailVO.getAttributeValue(field));
					targetKey.append(targetVo.getAttributeValue(field));
				}
				if (sourceKey.toString().contentEquals(targetKey)) {
					isMatch = true;
					amountSecondDown = targetVo.getAmount_seconddown();
					newStatus = VOStatus.UPDATED;
					nonMatchingList.remove(targetVo);
					iterator.remove();
					break;
				}
			}

			detailVO.setAmount_seconddown(amountSecondDown);

			if (detailVO.getStatus() != VOStatus.DELETED
					&& StringUtils.isNotEmpty(detailVO.getPk_budgetmakedetail())) {
				detailVO.setStatus(newStatus);
			}
			newMakeDetailBodys.add(detailVO);
		}
		if (nonMatchingList.size() != 0) {
			isMatch = true;
			for (BudgetMakeDetailVO targetVo : nonMatchingList) {
				BudgetMakeDetailVO newdetailVo = new BudgetMakeDetailVO();
				for (String field : activeBudgetDim) {
					newdetailVo.setAttributeValue(field, targetVo.getAttributeValue(field));
				}
				newdetailVo.setAmount_seconddown(targetVo.getAmount_seconddown());
				newdetailVo.setStatus(2);
				newMakeDetailBodys.add(newdetailVo);
			}
		}
		if(newMakeDetailBodys.size() < detailVOS.length + nonMatchingList.size() || !isMatch){
			throw new BusinessException("汇总维度匹配不到数据。");
		}

		vo.setChildrenVO(newMakeDetailBodys.toArray(new BudgetMakeDetailVO[0]));

		return vo;
	}

	private static StringBuilder getVoValueByDim(BudgetMakeDetailVO headPoint) {
		StringBuilder headPointKey = new StringBuilder();
		for (String dim : dimFields) {
			headPointKey.append(headPoint.getAttributeValue(dim));
		}
		return headPointKey;
	}

	@Override
	public AggBudgetMakeVO[] splitRowsByOperation(AggBudgetMakeVO vo, String key) throws BusinessException {
		AggBudgetMakeVO[] vos = new AggBudgetMakeVO[1];
		AbstractBill[] resultAbvos = new AbstractBill[0];
		List<AggBudgetMakeVO> result = new ArrayList<>();
		BudgetMakeDetailVO[] bodyvos = (BudgetMakeDetailVO[]) vo.getChildren(BudgetMakeDetailVO.class);
		GovpurchVO[] govpurchVOS = (GovpurchVO[]) vo.getChildren(GovpurchVO.class);
		AssetAllocationVO[] assetAllocationVOS = (AssetAllocationVO[]) vo.getChildren(AssetAllocationVO.class);
		if (Objects.nonNull(assetAllocationVOS) && assetAllocationVOS.length > 0 && "pk_material".equals(key)) {
			List<AssetAllocationVO> newBodyvos = new ArrayList<AssetAllocationVO>();
			List<AssetAllocationVO> noNeedSplitRow = new ArrayList<AssetAllocationVO>();
			for (AssetAllocationVO bodyvo : assetAllocationVOS) {
				if (Objects.nonNull(bodyvo.getAttributeValue(key))) {
					String[] pks = bodyvo.getAttributeValue(key).toString().split(",");
					if (pks.length > 1) {
						AssetAllocationVO oldDetailVO = (AssetAllocationVO) bodyvo.clone();
						for (int i = 0; i < pks.length; i++) {
							if (i == 0) {
								oldDetailVO.setAttributeValue(key, pks[0]);
								newBodyvos.add(oldDetailVO);
							} else {
								bodyvo.setAttributeValue("rowid", null);
								bodyvo.setAttributeValue(key, null);
								String[] attrs = bodyvo.getAttributeNames();
								for (String attr : attrs) {
									if (!Arrays.asList(SplitRowCopyItems.copyAssItems).contains(attr)) {
										bodyvo.setAttributeValue(attr, null);
									}
								}
								AssetAllocationVO bvo = (AssetAllocationVO) bodyvo.clone();
								bvo.setAttributeValue(key, pks[i]);
								bvo.setStatus(2);
								newBodyvos.add(bvo);
							}
						}
					} else {
						noNeedSplitRow.add(bodyvo);
					}
				} else {
					noNeedSplitRow.add(bodyvo);
				}
			}
			newBodyvos.addAll(noNeedSplitRow);
			vo.setChildren(AssetAllocationVO.class, newBodyvos.toArray(new AssetAllocationVO[0]));
			vos[0] = vo;
		}
		if (Objects.nonNull(govpurchVOS) && govpurchVOS.length > 0 && "pk_project".equals(key)) {
			List<GovpurchVO> newBodyvos = new ArrayList<GovpurchVO>();
			List<GovpurchVO> noNeedSplitRow = new ArrayList<GovpurchVO>();
			for (GovpurchVO bodyvo : govpurchVOS) {
				if (Objects.nonNull(bodyvo.getAttributeValue(key))) {
					String[] pks = bodyvo.getAttributeValue(key).toString().split(",");
					if (pks.length > 1) {
						GovpurchVO oldDetailVO = (GovpurchVO) bodyvo.clone();
						for (int i = 0; i < pks.length; i++) {
							if (i == 0) {
								oldDetailVO.setAttributeValue(key, pks[0]);
								newBodyvos.add(oldDetailVO);
							} else {
								bodyvo.setAttributeValue("rowid", null);
								bodyvo.setAttributeValue(key, null);
								String[] attrs = bodyvo.getAttributeNames();
								for (String attr : attrs) {
									if (!Arrays.asList(SplitRowCopyItems.copyGovItems).contains(attr)) {
										bodyvo.setAttributeValue(attr, null);
									}
								}
								GovpurchVO bvo = (GovpurchVO) bodyvo.clone();
								bvo.setAttributeValue(key, pks[i]);
								bvo.setStatus(2);
								newBodyvos.add(bvo);
							}
						}
					} else {
						noNeedSplitRow.add(bodyvo);
					}
				} else {
					noNeedSplitRow.add(bodyvo);
				}
			}
			newBodyvos.addAll(noNeedSplitRow);
			vo.setChildren(GovpurchVO.class, newBodyvos.toArray(new GovpurchVO[0]));
			vos[0] = vo;
		}
		if (bodyvos.length > 0) {
			List<BudgetMakeDetailVO> newBodyvos = new ArrayList<BudgetMakeDetailVO>();
			List<BudgetMakeDetailVO> noNeedSplitRow = new ArrayList<BudgetMakeDetailVO>();
			for (BudgetMakeDetailVO bodyvo : bodyvos) {
				if (Objects.nonNull(bodyvo.getAttributeValue(key))) {
					String[] pks = bodyvo.getAttributeValue(key).toString().split(",");
					if (pks.length > 1) {
						BudgetMakeDetailVO oldDetailVO = (BudgetMakeDetailVO) bodyvo.clone();
						for (int i = 0; i < pks.length; i++) {
							if (i == 0) {
								oldDetailVO.setAttributeValue(key, pks[0]);
								newBodyvos.add(oldDetailVO);
							} else {
								bodyvo.setAttributeValue("rowid", null);
								bodyvo.setAttributeValue(key, null);
								String[] attrs = bodyvo.getAttributeNames();

								for (String attr : attrs) {
									if (!Arrays.asList(SplitRowCopyItems.coypItems).contains(attr)) {
										bodyvo.setAttributeValue(attr, null);
									}
								}
								BudgetMakeDetailVO bvo = (BudgetMakeDetailVO) bodyvo.clone();
								bvo.setAttributeValue(key, pks[i]);
								bvo.setStatus(2);
								newBodyvos.add(bvo);
							}
						}
					} else {
						noNeedSplitRow.add(bodyvo);
					}
				} else {
					noNeedSplitRow.add(bodyvo);
				}
			}
			newBodyvos.addAll(noNeedSplitRow);
			vo.setChildren(BudgetMakeDetailVO.class, newBodyvos.toArray(new BudgetMakeDetailVO[0]));
			vos[0] = vo;
		}
		String pk_budgettype = (String) vo.getParentVO().getAttributeValue("pk_budgettype");
		String pk_budgetdept = (String) vo.getParentVO().getAttributeValue("pk_budgetdept");
		if (vo.getParentVO().getTranstype().indexOf("BD")>0){
			pk_budgetdept = (String) vo.getParentVO().getAttributeValue("pk_updept");
		}
		IBudgettypeService budgettypeService = NCLocator.getInstance().lookup(IBudgettypeService.class);
		Budgettype budgettype = budgettypeService.findBudgettypeByPk(pk_budgettype,false);
		String pk_topbudgettype = budgettype.getCode();
		if (Objects.nonNull(budgettype.getInnercode())){
			pk_topbudgettype = budgettype.getInnercode().substring(0,4);
		}
		boolean isfilter = this.checkInoutClassByYearTypeDept(vo.getParentVO().getNyear(),pk_topbudgettype,pk_budgetdept);
		if (isfilter && key.equals("pk_project")){
			resultAbvos = this.checkInoutClassByProjectAction(String.valueOf(isfilter),vo, BudgetMakeDetailVO.class);
			for (AbstractBill bill : resultAbvos) {
				AggBudgetMakeVO newAgg = (AggBudgetMakeVO) bill;
				result.add(newAgg);
			}
			return result.toArray(new AggBudgetMakeVO[0]);
		}
		return vos;
	}

	@Override
	public AggBudgetMakeVO budgetCal(AggBudgetMakeVO vo, String topcode) throws BusinessException {
		//获取表体维度
		IBudgettypeService budgettypeService = NCLocator.getInstance()
				.lookup(IBudgettypeService.class);
		IBudgetSchemeVOService budgetSchemeVOService = NCLocator.getInstance()
				.lookup(IBudgetSchemeVOService.class);
		Budgettype[] topType = this.dao.listByCondition(Budgettype.class, "code = '" + topcode + "'");
		if (Objects.isNull(topType)) {
			return vo;
		}
		AggBudgetSchemeVO[] aggBudgetSchemeVOS = budgetSchemeVOService
				.listAggBudgetSchemeVOByCondition(" pk_budgettype = '" + topType[0].getPk_budgettype()
						+ "' and nyear = '" + vo.getParentVO().getNyear() + "'");
		UFBoolean isuseDept = UFBoolean.TRUE;
		if (Objects.nonNull(aggBudgetSchemeVOS) && aggBudgetSchemeVOS.length > 0) {
			isuseDept = (UFBoolean) aggBudgetSchemeVOS[0].getChildren(BudgetMakeDetailVO.class)[4]
					.getAttributeValue("isusing");
		}
		// 表头年度、编制科室、预算类型赋值给表体字段
		SetChildColumnValue.setChildColumnValue(new AbstractBill[] { vo }, true);
		// 根据 预算类型、预算科室、年度查询预算测算设置
		StringBuffer condition = new StringBuffer();
		condition.append("dr=0 ");
		String[] budgettypePks = budgettypeService.listBudgettypePkByCond("code = '" + topcode + "'");
		if (Objects.nonNull(budgettypePks) && budgettypePks.length > 0) {
			condition.append(" and pk_budgettype = '" + budgettypePks[0] + "'");
		}
		condition.append(" and nyear = '" + vo.getParentVO().getNyear() + "'");
		condition.append(" and pk_budgetdept = '" + vo.getParentVO().getPk_budgetdept() + "'");
		IBudgetcalculateVOService budgetcalculateVOService = NCLocator.getInstance()
				.lookup(IBudgetcalculateVOService.class);

		AggBudgetcalculateMasterVO[] aggBudgetcalculateMasterVOS = budgetcalculateVOService
				.listAggBudgetcalculateMasterVOByCondition(condition.toString());
		// 根据aggBudgetcalculateMasterVOs的子表，获得各个指标的值得查询条件，以及公式
		Map<String, CalculateItems> calculateItemsList = new HashMap<String, CalculateItems>();
		if (Objects.nonNull(aggBudgetcalculateMasterVOS) && aggBudgetcalculateMasterVOS.length > 0) {
			for (AggBudgetcalculateMasterVO aggvo : aggBudgetcalculateMasterVOS) {
				BudgetcalculateSlaveVO[] slaveVOS = (BudgetcalculateSlaveVO[]) aggvo
						.getChildren(BudgetcalculateSlaveVO.class);
				for (BudgetcalculateSlaveVO slaveVO : slaveVOS) {
					String rowkey = getRowKey(slaveVO);
					calculateItemsList.put(rowkey,
							(new CalculateItems.Builder()).rowkey(getRowKey(slaveVO))
									.formula(slaveVO.getFormula())
									.formulaInfoVOS(generalFormulaInfos(vo, slaveVO, aggvo, topcode, isuseDept))
									.formulaValues(this.formulaValues).percentage(slaveVO.getCalculationratio())// 百分比
									.build());
				}
			}
			// 计算，并向表体插入数值
			if (calculateItemsList.keySet().size() > 0) {
				for (BudgetMakeDetailVO detailVo : (BudgetMakeDetailVO[]) vo.getChildren(BudgetMakeDetailVO.class)) {
					String rowkey = getRowKey(detailVo);
					for (String pk : calculateItemsList.keySet()) {
						if (rowkey.equals(calculateItemsList.get(pk).getRowkey())) {
							String formula = CalculationFormulaUtils.changeNameFormulaToCodeFormula(
									calculateItemsList.get(pk).getFormula());
							Object result = CalculationFormulaUtils.CalculationFormulaForOperationIndicator(
									String.valueOf(formula),
									calculateItemsList.get(pk).getFormulaValues());
							//一上=1,一下=2,二上=3,二下=4,预算编制=5,一上测算时取值到一上预算数，二上测算时，其取值到二上预算数。
							if (vo.getParentVO().getTaskstage().equals(TaskStageEnum.FirstUp.toIntValue())) {
								detailVo.setAmount_firstup(new UFDouble(result.toString()));// 一上预算数
							} else if (vo.getParentVO().getTaskstage().equals(TaskStageEnum.SecondUp.toIntValue())){
								detailVo.setAmount_secondup(new UFDouble(result.toString()));// 二上预算数
							}
							else if (detailVo.getPk_budgettype().equals("YS05")) {
								detailVo.setAmount_seconddown(new UFDouble(Double.parseDouble(result.toString()))); // 二下批复数
							}else {
								detailVo.setAmount_firstup(new UFDouble(result.toString())); // 二下批复数
							}
						}
					}
				}
			}
		}
		return vo;
	}


	@Override
	public AggBudgetMakeVO[] queryBudgetMakeByPk_summarydetails(String pk) throws BusinessException {
		String condition = "pk_summarybill = '" + pk + "'";
		return listAggBudgetMakeVOByCondition(condition, null);
	}
	@Override
	public AggBudgetMakeVO[] copyBudgetMake(AggBudgetMakeVO aggBudgetMakeVO, CopyBudgetMakeVO copyBudgetMakeVO)
			throws BusinessException {
		//依据组织，编制科室，预算类型，编制方案。自动加载历史年度对应编制单中的预算数据到到当前表体数据中
		/**
		 * 1、校验编制方案是否相同
		 * 2、获取历史的编报完成的编制数据
		 * 3、过滤含有停用档案的编制明细
		 * 4、组装aggvo
		 * */
//        aggBudgetMakeVO.setChildren(BudgetMakeDetailVO.class,null);
		List<BudgetMakeDetailVO> budgetMakeDetailVOS = new ArrayList<>();
		BudgetMakeDetailVO[] oldDetailvos = (BudgetMakeDetailVO[]) aggBudgetMakeVO.getChildren(BudgetMakeDetailVO.class);

		if (Objects.nonNull(oldDetailvos)){
			for (BudgetMakeDetailVO o:oldDetailvos
			) {
				if (Objects.nonNull(o.getPk_budgetmakedetail())){
					o.setStatus(VOStatus.DELETED);
					budgetMakeDetailVOS.add(o);
				}
			}
		}
		List<String> currentYearShowColumn = iHrpbmCommonService.findHideCloumnByTypeYear(copyBudgetMakeVO.getTopcode(),aggBudgetMakeVO.getParentVO().getNyear(),true);
		List<String> copyYearShowColumn = iHrpbmCommonService.findHideCloumnByTypeYear(copyBudgetMakeVO.getTopcode(),copyBudgetMakeVO.getCopynyear(),true);
		this.checkShowColumn(currentYearShowColumn,copyYearShowColumn);

		/**
		 * 处理查询类型 "amount"://年度最终预算数 "amount_firstup"://一上预算数 "executeamount"://执行数
		 * "make" 查询编制单，"ctrl" 查询控制平台
		 */
		if(copyBudgetMakeVO.getCopytype().split("@@").length!=2){
			ExceptionUtils.wrapBusinessException("数据类型的值不正确，请调整模板");
		}
		String copyFromModelName = copyBudgetMakeVO.getCopytype().split("@@")[0];
		String copyAmountColumnName = copyBudgetMakeVO.getCopytype().split("@@")[1];
		List<BudgetMakeDetailVO> result = new ArrayList<>();
		switch (copyFromModelName){
			case "make":
				result = this.dealChildVOFromMake(aggBudgetMakeVO,copyBudgetMakeVO.getCopynyear(),copyAmountColumnName);
				break;
			case "ctrl":
				result = this.dealChildVOFromCtrl(aggBudgetMakeVO,copyBudgetMakeVO.getCopynyear(),copyAmountColumnName);
				break;
			default:
				ExceptionUtils.wrapBusinessException("数据类型指定的模块名称不正确，请调整模板");
				break;
		}
		if (result.isEmpty()){
			ExceptionUtils.wrapBusinessException("没有查询到预算历史数据。");
		}
		this.filterDisableDoc(result);
		result.addAll(budgetMakeDetailVOS);
		aggBudgetMakeVO.setChildren(BudgetMakeDetailVO.class,result.toArray(new BudgetMakeDetailVO[0]));

		return new AggBudgetMakeVO[]{aggBudgetMakeVO};
	}

	@Override
	public AggBudgetMakeVO[] getIndicatorData(AggBudgetMakeVO aggBudgetMakeVO) throws BusinessException {
		List<BudgetMakeDetailVO> budgetMakeDetailVOS = new ArrayList<>();

		BudgetMakeDetailVO[] oldDetailvos = (BudgetMakeDetailVO[]) aggBudgetMakeVO.getChildren(BudgetMakeDetailVO.class);

		if (Objects.nonNull(oldDetailvos)){
			for (BudgetMakeDetailVO o:oldDetailvos
			) {
				if (Objects.nonNull(o.getPk_budgetmakedetail())){
					o.setStatus(VOStatus.DELETED);
					budgetMakeDetailVOS.add(o);
				}
			}
		}

		AggBudgetIndicatorVO aggBudgetIndicatorVO = this.queryAggBudgetIndicatorVO(aggBudgetMakeVO.getParentVO().getPk_org(),
				aggBudgetMakeVO.getParentVO().getNyear(),aggBudgetMakeVO.getParentVO().getPk_budgettype(),
				aggBudgetMakeVO.getParentVO().getPk_budgetdept());
		if (Objects.isNull(aggBudgetIndicatorVO) || aggBudgetIndicatorVO.getParentVO().getIndicatordim().equals(1)){
			ExceptionUtils.wrapBusinessException("没有查询到预算指标下达数据。");
		}else {//dimFields
			for (BudgetIndicatorBVO indicatorBVO: (BudgetIndicatorBVO[])aggBudgetIndicatorVO.getChildren(BudgetIndicatorBVO.class)) {
				BudgetMakeDetailVO detailVO = new BudgetMakeDetailVO();
				detailVO.setStatus(VOStatus.NEW);
				detailVO.setIndicatoramount(indicatorBVO.getAmount());
				detailVO.setAmount_firstup(indicatorBVO.getAmount());
				for (String s : dimFields) {
					detailVO.setAttributeValue(s,indicatorBVO.getAttributeValue(s));
				}
				if (StringUtils.isEmpty(detailVO.getPk_budgetmakedetail())){
					detailVO.setStatus(VOStatus.NEW);
				}else{
					detailVO.setStatus(VOStatus.UPDATED);
				}
				budgetMakeDetailVOS.add(detailVO);

			}
			aggBudgetMakeVO.setChildren(BudgetMakeDetailVO.class,null);
			aggBudgetMakeVO.setChildren(BudgetMakeDetailVO.class,budgetMakeDetailVOS.toArray(new BudgetMakeDetailVO[0]));
		}
		return new AggBudgetMakeVO[]{aggBudgetMakeVO};
	}

	@Override
	public Map<String, Object> validateProject(AggBudgetMakeVO aggBudgetMakeVO) throws BusinessException {
		StringBuffer errmsg = new StringBuffer();
		StringBuffer warning = new StringBuffer();
		Map<String,Object> externalData = new HashMap<>();
		ValidateProject validateProject = new ValidateProject();
		validateProject.validateProject(aggBudgetMakeVO, BudgetMakeDetailVO.class,errmsg,warning);
//        externalData.put("messageOfvalidateProject", errmsg.toString());
		if (errmsg.length() > 0 ) throw new BusinessException(errmsg.toString());
		if (warning.length() > 0){
			externalData.put("messageOfvalidateProject", warning.toString());
		}
		return externalData;
	}

	/**
	 * 新增：用户录入“预算编制明细”中的所有项目，如果项目档案属性中勾选“是否绩效考核”为是，
	 * 点“绩效目标”按钮，自动弹出项目绩效目标单据，默认新增态：依据项目库项目绩效信息页签加载明细记录，
	 * 表头项目，预算科室，年度自动带入，不可编辑;项目预期目标可编辑。表体，指标名称，指标评分占比，年度目标可编辑，可增删行，保存。
	 * 如果不存在当前项目绩效目标时，单据为新增态; 如果已存在项目目标单时，打开单据默认为查询态，可修改。
	 * */
	@Override
	public Map<String, Object> dealAddProjectGoals(AbstractBill vo, String pk_project) throws BusinessException {
		Map<String,Object> result = new HashMap<>();
		result.put("pk_budgetdept",vo.getParentVO().getAttributeValue("pk_budgetdept"));
		result.put("nyear",vo.getParentVO().getAttributeValue("nyear"));
		result.put("pk_project",pk_project);
		result.put("pk_budgettype",vo.getParentVO().getAttributeValue("pk_budgettype"));
		result.put("pk_org",vo.getParentVO().getAttributeValue("pk_org"));
		//一上，二上编制单都可以点“绩效目标”按钮进行操作。单据自由态时，绩效目标可编辑，非自由态时，只读。
		if (!vo.getParentVO().getAttributeValue("approvestatus").equals(BillStatusEnum.FREE.toIntValue())){
			result.put("onlyBrowse",true);
		}else{
			result.put("onlyBrowse",false);
		}
		ProjectHeadVO[] projectHeadVO = dao.listByCondition(ProjectHeadVO.class,"pk_project = '"+pk_project+"'");
		if (Objects.nonNull(projectHeadVO) && projectHeadVO.length>0){
			UFBoolean bperformance = Objects.nonNull(projectHeadVO[0].getAttributeValue("bperformance"))?new UFBoolean(projectHeadVO[0].getAttributeValue("bperformance").toString()):UFBoolean.FALSE;
			if (!bperformance.booleanValue()){
				throw new BusinessException("项目："+projectHeadVO[0].getProject_name()+"，未勾选是否绩效考核。");
			}
			Budgettype[] budgettypes = dao.listByPk(Budgettype.class,new String[]{vo.getParentVO().getAttributeValue("pk_budgettype").toString()});
			if (budgettypes.length>0) {
				String topcode = budgettypes[0].getInnercode().substring(0, 4);
				Budgettype[] budgettypes1 = dao.listByCondition(Budgettype.class, "code = '" + topcode + "'");
				if (budgettypes1.length>0){
					IBudgetPerformanceGoalsMasterVOService performanceGoalsMasterVOService = NCLocator.getInstance().lookup(IBudgetPerformanceGoalsMasterVOService.class);
					BudgetPerformanceGoalsMasterVO[] performanceGoalsMasterVOS =
							performanceGoalsMasterVOService.listBudgetPerformanceGoalsMasterVOByCondition
									("pk_project = '"+pk_project+"' " +
											"and pk_budgetdept = '"+vo.getParentVO().getAttributeValue("pk_budgetdept")+"' " +
											"and nyear = '"+vo.getParentVO().getAttributeValue("nyear")+"' " +
											"and pk_org = '"+vo.getParentVO().getAttributeValue("pk_org")+"' " +
//                                            "and pk_org = '"+projectHeadVO[0].getPk_org()+"' " +
											"and pk_budgettype = '"+budgettypes1[0].getPk_budgettype()+"'");
					if (Objects.nonNull(performanceGoalsMasterVOS) && performanceGoalsMasterVOS.length>0){
						result.put("id",performanceGoalsMasterVOS[0].getPk_performancegoals());
					}
				}
			}
		}
		return result;
	}

	@Override
	public AbstractBill[] checkInoutClassByProjectAction(String isfilter,AbstractBill vo,Class<? extends ISuperVO> clazz) throws BusinessException {
		if (Objects.nonNull(vo) && UFBoolean.valueOf(isfilter).booleanValue()){
			String pk_budgettype = (String) vo.getParentVO().getAttributeValue("pk_budgettype");
			IBudgettypeService budgettypeService = NCLocator.getInstance().lookup(IBudgettypeService.class);
			Budgettype budgettype = budgettypeService.findBudgettypeByPk(pk_budgettype,false);
			String pk_topbudgettype = budgettype.getInnercode().substring(0,4);
			SuperVO[] bvos = (SuperVO[]) vo.getChildren(clazz);
			if (Objects.nonNull(bvos)){
				for (SuperVO bvo:bvos) {
					String inoutclassPk = Objects.nonNull(bvo.getAttributeValue("pk_inoutclass"))?bvo.getAttributeValue("pk_inoutclass").toString():"";
					String year = Objects.nonNull(vo.getParentVO().getAttributeValue("nyear"))?vo.getParent().getAttributeValue("nyear").toString():"";
					String pk_budgetdept = Objects.nonNull(vo.getParentVO().getAttributeValue("pk_budgetdept"))?vo.getParent().getAttributeValue("pk_budgetdept").toString():"";
					if (vo.getParentVO().getAttributeValue("transtype").toString().indexOf("BD")>0){
						pk_budgetdept = (String) vo.getParentVO().getAttributeValue("pk_updept");
					}
					String projectPK = Objects.nonNull(bvo.getAttributeValue("pk_project"))?bvo.getAttributeValue("pk_project").toString():"";
					StringBuffer sql = new StringBuffer();
					sql.append(" select pk_inoutclass from hrpbm_dimassign mass ");
					sql.append(
							" left join hrpbm_dimassign_inoutclass inoutclass on mass.pk_dimassign = inoutclass.pk_dimassign ");
					sql.append(" where mass.nyear = '");
					sql.append(year);
					sql.append("' and mass.pk_budgetdept = '");
					sql.append(pk_budgetdept);
					sql.append("' and mass.pk_budgettype = (select PK_BUDGETTYPE from HRPBM_BUDGETTYPE where code ='");
					sql.append(pk_topbudgettype).append("' )");
					if (StringUtils.isNotEmpty(projectPK)){
						sql.append(" and inoutclass.PK_INOUT_PROJECT ='"+ projectPK+"' ");
					}
					try {
						List<String> inoutclass = (List<String>) dao.getBaseDAO().executeQuery(sql.toString(),new ColumnListProcessor("pk_inoutclass"));
						if (!inoutclass.isEmpty()){
							if (!inoutclass.contains(inoutclassPk)){
								bvo.setAttributeValue("pk_inoutclass",null);
							}
						}else{
							bvo.setAttributeValue("pk_inoutclass",null);
						}
					} catch (DAOException e) {
						throw new RuntimeException(e);
					}
				}
			}
			vo.setChildren(clazz,bvos);
		}
		return new AbstractBill[]{vo};
	}

	/**
	 * 获取预算数
	 * 预算类型：只显示预算一级大类（去掉资金预算）
	 * 预数比例：手工录入，默认100，按取得预算数乘以此比例*100%取得计算后数据。
	 * 加载方式：追加/覆盖/更新。追加，是在表体最后追加新行;覆盖:清空表体数据，重新生成表体行。更新：更新当前行预算数，现有逻辑。
	 * 点“确定”进行取数，其他取数逻辑不变。取点消，关闭当前窗口，不做操作。
	 * 如果资金预算编制方案中启用“预算科室”维度，取数也按编制单表头“预算科室”对应预算类型“编制科室”的数据。如果没有启用“预算科室”维度，取数只按表体维度汇总所有预算数据。
	 * 如果表体取数维度不一致，则不进行取数，给出提示：汇总维度匹配不到数据。
	 * @param vo
	 * @param map budgetType 预算一级大类   dataFetchRatio  预数比例   loadType 加载方式：覆盖=1,追加=2,更新=3
	 * @return
	 */
	@Override
	public AggBudgetMakeVO fetchBudgetData(AggBudgetMakeVO vo, Map<String, Object> map) throws BusinessException {
		// budgetType 预算一级大类
		String pk_budgetType = map.get("budgetType").toString();
		// dataFetchRatio 预数比例
		UFDouble dataFetchRatio = new UFDouble(map.get("dataFetchRatio").toString());
		// loadType 加载方式：追加 1 /覆盖 2 /更新 3
		Integer loadType = Integer.valueOf(map.get("loadType").toString());

		BudgetMakeVO parentVO = vo.getParentVO();
		BudgetMakeDetailVO[] detailVOS = (BudgetMakeDetailVO[]) vo.getChildren(BudgetMakeDetailVO.class);
		IBudgettypeService budgetTypeService = NCLocator.getInstance().lookup(IBudgettypeService.class);
		Budgettype budgettype = budgetTypeService.findBudgettypeByPk(pk_budgetType, false);

		List<String> sourceActiveDim = BudgetCalUtil.getActiveBudgetDim(parentVO.getPk_budgettype(), parentVO.getNyear());
		List<String> targetActiveDim = BudgetCalUtil.getActiveBudgetDim(pk_budgetType, parentVO.getNyear());
		if(!sourceActiveDim.containsAll(targetActiveDim)){
			throw new BusinessException("汇总维度匹配不到数据。");
		}
		// Build SQL query
		String sql = String.format(
				"SELECT pk_inoutclass, pk_project, pk_fundsource, pk_operation, pk_budgetdept, defdim1, defdim2, " +
						"defdim3, defdim4, defdim5, defdim6, defdim7, defdim8, defdim9, defdim10, nyear, SUM(amount) amount_seconddown " +
						"FROM hrpbm_budgetmakedetail WHERE pk_budgetmake IN (SELECT pk_budgetmake FROM hrpbm_budgetmake " +
						"WHERE pk_org = '%s' AND nyear = '%s' and dr = 0 AND  taskstate = '99' AND transtype LIKE '%%CD-%s') and dr = 0 " +
						"GROUP BY pk_inoutclass, pk_project, pk_fundsource, pk_operation, pk_budgetdept, defdim1, defdim2, " +
						"defdim3, defdim4, defdim5, defdim6, defdim7, defdim8, defdim9, defdim10, nyear",
				vo.getParentVO().getPk_org(), vo.getParentVO().getNyear(), budgettype.getCode()
		);

		List<BudgetMakeDetailVO> dataList = (List<BudgetMakeDetailVO>) dao.getBaseDAO().executeQuery(sql, new BeanListProcessor(BudgetMakeDetailVO.class));
		if (Objects.isNull(dataList) || dataList.isEmpty()) {
			throw new BusinessException("汇总维度匹配不到数据。");
		}

		List<BudgetMakeDetailVO> newMakeDetailBodys = new ArrayList<>();
		Map<String, BudgetMakeDetailVO> dimensionalGroupingMap = new HashMap<>();
		combineDetailsByDimension(dataList, sourceActiveDim,parentVO.getPk_budgetdept(),dimensionalGroupingMap);

		switch (loadType) {
			case 1 : {
				// 覆盖
				for (BudgetMakeDetailVO detailVO : detailVOS) {
					detailVO.setStatus(VOStatus.DELETED);
					newMakeDetailBodys.add(detailVO);
				}
				newMakeDetailBodys.addAll(dimensionalGroupingMap.values());
				applyFetchRatio(newMakeDetailBodys, dataFetchRatio);
				vo.setChildrenVO(newMakeDetailBodys.toArray(new BudgetMakeDetailVO[0]));
				return vo;
			}
			case 2 : {
				// 追加 原表体数据 + 获取的表体数据
				applyFetchRatio(dataList, dataFetchRatio);
				List<BudgetMakeDetailVO> detailList = new ArrayList<>(Arrays.asList(detailVOS));
				newMakeDetailBodys.addAll(detailList);
				newMakeDetailBodys.addAll(dimensionalGroupingMap.values());
				vo.setChildrenVO(newMakeDetailBodys.toArray(new BudgetMakeDetailVO[0]));
				return vo;
			}
			case 3 : {
				// 更新
				updateOrAddDetails(detailVOS, dimensionalGroupingMap.values(), newMakeDetailBodys, sourceActiveDim,dataFetchRatio);
				vo.setChildrenVO(newMakeDetailBodys.toArray(new BudgetMakeDetailVO[0]));
				return vo;
			}
			default : throw new BusinessException("无效的加载方式。");
//            case 1 -> {
//                // 覆盖
//                for (BudgetMakeDetailVO detailVO : detailVOS) {
//                    detailVO.setStatus(VOStatus.DELETED);
//                    newMakeDetailBodys.add(detailVO);
//                }
//                newMakeDetailBodys.addAll(dimensionalGroupingMap.values());
//                applyFetchRatio(newMakeDetailBodys, dataFetchRatio);
//            }
//            case 2 -> {
//                // 追加 原表体数据 + 获取的表体数据
//                applyFetchRatio(dataList, dataFetchRatio);
//                List<BudgetMakeDetailVO> detailList = new ArrayList<>(Arrays.asList(detailVOS));
//                newMakeDetailBodys.addAll(detailList);
//                newMakeDetailBodys.addAll(dimensionalGroupingMap.values());
//            }
//            case 3 -> {
//                // 更新
//                updateOrAddDetails(detailVOS, dimensionalGroupingMap.values(), newMakeDetailBodys, sourceActiveDim,dataFetchRatio);
//            }
//            default -> throw new BusinessException("无效的加载方式。");

		}
//        vo.setChildrenVO(newMakeDetailBodys.toArray(new BudgetMakeDetailVO[0]));
//        return vo;
	}

	private static void checkBudgetDeptDim(BudgetMakeVO parentVO, List<String> activeBudgetDim,
										   List<BudgetMakeDetailVO> dataList, List<BudgetMakeDetailVO> newMakeDetailBodys) {
		if(activeBudgetDim.contains("pk_budgetdept")){
			for (BudgetMakeDetailVO makeDetailVO : dataList) {
				if(StringUtils.isNotEmpty(makeDetailVO.getPk_budgetdept()) && makeDetailVO.getPk_budgetdept().equals(parentVO.getPk_budgetdept())){
					newMakeDetailBodys.add(makeDetailVO);
				}
			}
		}
	}

	private void combineDetailsByDimension(List<BudgetMakeDetailVO> dataList,
										   List<String> activeBudgetDim,
										   String pk_budgetdept,
										   Map<String, BudgetMakeDetailVO> dimensionalGroupingMap) {

		for (Iterator<BudgetMakeDetailVO> iterator = dataList.iterator(); iterator.hasNext(); ) {
			BudgetMakeDetailVO item = iterator.next();
			if(activeBudgetDim.contains("pk_budgetdept")
					&& StringUtils.isNotEmpty(item.getPk_budgetdept())
					&& !item.getPk_budgetdept().equals(pk_budgetdept)){
				continue;
			}
			String key = activeBudgetDim.stream()
					.map(field -> Objects.toString(item.getAttributeValue(field), "null"))
					.collect(Collectors.joining());

			dimensionalGroupingMap.merge(key, item, (existing, newItem) -> {
				existing.setAmount_seconddown(existing.getAmount_seconddown().add(newItem.getAmount_seconddown()));
				return existing;
			});
		}
	}

	private void updateOrAddDetails(BudgetMakeDetailVO[] detailVOS,
									Collection<BudgetMakeDetailVO> dataList,
									List<BudgetMakeDetailVO> newMakeDetailBodys,
									List<String> activeBudgetDim,
									UFDouble dataFetchRatio) throws BusinessException {
		//未匹配到的数据
		List<BudgetMakeDetailVO> nonMatchingList = new ArrayList<>(dataList);
		// 是否存在匹配数据
		boolean isMatch = false;

		for (BudgetMakeDetailVO detailVO : detailVOS) {
			if (detailVO.getStatus() == VOStatus.DELETED) {
				newMakeDetailBodys.add(detailVO);
				continue;
			}
			// 初始化默认值
			UFDouble amountSecondDown = detailVO.getAmount_seconddown();
			int newStatus = VOStatus.UNCHANGED;
			//使用 Objects.toString() 方法来安全地转换 null 值
			String sourceKey = activeBudgetDim.stream()
					.filter(field -> !field.equals("pk_budgetdept"))
					.map(field -> Objects.toString(detailVO.getAttributeValue(field), "null"))
					.collect(Collectors.joining());

			for (Iterator<BudgetMakeDetailVO> iterator = dataList.iterator(); iterator.hasNext(); ) {
				BudgetMakeDetailVO targetVo = iterator.next();
				//使用 Objects.toString() 方法来安全地转换 null 值
				String targetKey = activeBudgetDim.stream()
						.filter(field -> !field.equals("pk_budgetdept"))
						.map(field -> Objects.toString(targetVo.getAttributeValue(field), "null"))
						.collect(Collectors.joining());


				if (sourceKey.equals(targetKey)) {
					isMatch = true;
					amountSecondDown = targetVo.getAmount_seconddown().multiply(dataFetchRatio).div(100);
					newStatus = VOStatus.UPDATED;
					nonMatchingList.remove(targetVo);
					iterator.remove();
					break;
				}
			}

			detailVO.setAmount_seconddown(amountSecondDown);
			detailVO.setStatus(newStatus);
			newMakeDetailBodys.add(detailVO);
		}

		if (nonMatchingList.size() != 0) {
			isMatch = true;
			for (BudgetMakeDetailVO targetVo : nonMatchingList) {
				BudgetMakeDetailVO newDetailVo = new BudgetMakeDetailVO();
				for (String field : activeBudgetDim) {
					newDetailVo.setAttributeValue(field, targetVo.getAttributeValue(field));
				}
				newDetailVo.setAmount_seconddown(targetVo.getAmount_seconddown());
				newDetailVo.setStatus(VOStatus.NEW);
				newMakeDetailBodys.add(newDetailVo);
			}
		}


		if (newMakeDetailBodys.size() < detailVOS.length + nonMatchingList.size() || !isMatch) {
			throw new BusinessException("汇总维度匹配不到数据。");
		}
	}
	private void applyFetchRatio(List<BudgetMakeDetailVO> newMakeDetailBodys, UFDouble dataFetchRatio) {
		for (BudgetMakeDetailVO newMakeDetailBody : newMakeDetailBodys) {
			newMakeDetailBody.setAmount_seconddown(
					newMakeDetailBody.getAmount_seconddown().multiply(dataFetchRatio).div(100)
			);
		}
	}

	private List<BudgetMakeDetailVO> dealChildVOFromMake(AggBudgetMakeVO aggBudgetMakeVO,String copynyear,String copyAmountColumnName) throws BusinessException {
		Integer taskstage = aggBudgetMakeVO.getParentVO().getTaskstage();
		String condition = " pk_org = '"+aggBudgetMakeVO.getParentVO().getPk_org()+"' " +
				"and pk_budgetdept = '"+aggBudgetMakeVO.getParentVO().getPk_budgetdept()+"' " +
				"and nyear = '"+copynyear+"' " +
				"and pk_budgettype = '"+aggBudgetMakeVO.getParentVO().getPk_budgettype()+"' " +
				"and taskstate = 99";
		AggBudgetMakeVO[] aggBudgetMakeVOSOfCopyNyear = this.listAggBudgetMakeVOByCondition(condition);
		List<BudgetMakeDetailVO> alldetails = new ArrayList<>();
		if (Objects.nonNull(aggBudgetMakeVOSOfCopyNyear)){
			for (AggBudgetMakeVO aggvo :
					aggBudgetMakeVOSOfCopyNyear) {
				alldetails.addAll(
						this.dealCopyDetailVO(
								(BudgetMakeDetailVO[]) aggvo.getChildren(BudgetMakeDetailVO.class),copyAmountColumnName,taskstage));
			}
		}
		return alldetails;
	}

	private List<BudgetMakeDetailVO> dealChildVOFromCtrl(AggBudgetMakeVO aggBudgetMakeVO,String copynyear,String copyAmountColumnName) throws BusinessException {
		Integer taskstage = aggBudgetMakeVO.getParentVO().getTaskstage();
		List<BudgetMakeDetailVO> alldetails = new ArrayList<>();
		String condition = " pk_org = '"+aggBudgetMakeVO.getParentVO().getPk_org()+"' " +
				"and pk_budgetdept = '"+aggBudgetMakeVO.getParentVO().getPk_budgetdept()+"' " +
				"and nyear = '"+copynyear+"' " +
				"and pk_budgettype = '"+aggBudgetMakeVO.getParentVO().getPk_budgettype()+"' " +
				"and taskstate = 99";
		AggBudgetMakeVO[] aggBudgetMakeVOSOfCopyNyear = this.listAggBudgetMakeVOByCondition(condition);
		List<String> pkdetails = new ArrayList<>();
		List<BudgetMakeDetailVO> budgetMakeDetailVOSOfCopyNyear = new ArrayList<>();
		if (Objects.nonNull(aggBudgetMakeVOSOfCopyNyear)){
			for (AggBudgetMakeVO aggvo :
					aggBudgetMakeVOSOfCopyNyear) {
				for (BudgetMakeDetailVO detailvo : (BudgetMakeDetailVO[])aggvo.getChildren(BudgetMakeDetailVO.class)) {
					pkdetails.add(detailvo.getPk_budgetmakedetail());
					budgetMakeDetailVOSOfCopyNyear.add(detailvo);
				}
			}
		}
		String inSqlManager = InSqlManager.getInSQLValue(pkdetails);
		condition = "BUSIBILLBID in " +inSqlManager;
		BusiCtrlDataVO[] ctrlDataVOS = dao.listByCondition(BusiCtrlDataVO.class,condition);
		if (Objects.nonNull(ctrlDataVOS) && ctrlDataVOS.length>0){
			alldetails = this.dealCopyCtrlVO(ctrlDataVOS,budgetMakeDetailVOSOfCopyNyear,copyAmountColumnName,taskstage);
		}
		return alldetails;
	}

	private List<BudgetMakeDetailVO> dealCopyCtrlVO(BusiCtrlDataVO[] ctrlDataVOS,List<BudgetMakeDetailVO> budgetMakeDetailVOSOfCopyNyear, String copyAmountColumnName,Integer taskstage){
		List<BudgetMakeDetailVO> result = new ArrayList<>();
		Map<String,Object> valueOfCtrlMap = new HashMap<>();
		for (BusiCtrlDataVO ctrlvo : ctrlDataVOS) {
			valueOfCtrlMap.put(String.valueOf(ctrlvo.getBusibillbid()),ctrlvo.getAttributeValue(copyAmountColumnName));
		}
		for (BudgetMakeDetailVO detailVO :budgetMakeDetailVOSOfCopyNyear) {
			BudgetMakeDetailVO newDetail = new BudgetMakeDetailVO();
			for (String s:copyMakeFields) {
				newDetail.setStatus(VOStatus.NEW);
				newDetail.setAttributeValue(s,detailVO.getAttributeValue(s));
				if (taskstage != 5){
					newDetail.setAttributeValue(BudgetMakeDetailVO.AMOUNT_FIRSTUP,valueOfCtrlMap.get(detailVO.getPk_budgetmakedetail()));
				}else {
					newDetail.setAttributeValue(BudgetMakeDetailVO.AMOUNT_SECONDDOWN,valueOfCtrlMap.get(detailVO.getPk_budgetmakedetail()));
				}
			}
			result.add(newDetail);
		}
		return result;
	}

	private static final String[] copyMakeFields = {"pk_project","pk_inoutclass",
			"pk_fundsource","pk_operation",
			"def1","def2","def3","def4","def5","def6","def7","def8","def9","def10",
			"def11","def12","def13","def14","def15","def16","def17","def18","def19","def20",
			"defdim1", "defdim2", "defdim3", "defdim4", "defdim5", "defdim6", "defdim7", "defdim8", "defdim9", "defdim10"
	};

	private List<BudgetMakeDetailVO> dealCopyDetailVO(BudgetMakeDetailVO[] detailVOS,String copyAmountColumnName,Integer taskstage){
		List<BudgetMakeDetailVO> result = new ArrayList<>();
		for (BudgetMakeDetailVO detailVO :detailVOS) {
			BudgetMakeDetailVO newDetail = new BudgetMakeDetailVO();
			for (String s:copyMakeFields) {
				newDetail.setStatus(VOStatus.NEW);
				newDetail.setAttributeValue(s,detailVO.getAttributeValue(s));
				if (taskstage != 5){
					newDetail.setAttributeValue(BudgetMakeDetailVO.AMOUNT_FIRSTUP,detailVO.getAttributeValue(copyAmountColumnName));
				}else {
					newDetail.setAttributeValue(BudgetMakeDetailVO.AMOUNT_SECONDDOWN,detailVO.getAttributeValue(copyAmountColumnName));
				}

			}
			result.add(newDetail);
		}
		return result;
	}

	private void filterDisableDoc(List<BudgetMakeDetailVO> detailVOS) throws BusinessException {
		//pk_project
		List<ProjectHeadVO> disableProjects =
				Arrays.asList(dao.listByCondition(ProjectHeadVO.class,"enablestate = 3 and dr = 0"));
		//pk_inoutbusiclass
		List<InoutBusiClassVO> disableInouts =
				Arrays.asList(dao.listByCondition(InoutBusiClassVO.class,"enablestate = 3 and dr = 0"));
		//pk_fundsource
		List<FundSourceVO> disableFundsource =
				Arrays.asList(dao.listByCondition(FundSourceVO.class,"enablestate = 3 and dr = 0"));
		//pk_operation
		List<OperationalindicatorMasterVO> disableOperations =
				Arrays.asList(dao.listByCondition(OperationalindicatorMasterVO.class,"enablestate = 3 and dr = 0"));

		for (BudgetMakeDetailVO vo : detailVOS) {
			if (disableFundsource.contains(vo.getPk_fundsource())
					|| disableOperations.contains(vo.getPk_operation())
					|| disableInouts.contains(vo.getPk_inoutclass())
					|| disableProjects.contains(vo.getPk_project())
			){
				detailVOS.remove(vo);
			}
		}
	}

	private void  checkShowColumn(List<String> currentYearShowColumn,List<String> copyYearShowColumn){
		if (!currentYearShowColumn.equals(copyYearShowColumn)){
			ExceptionUtils.wrapBusinessException("历史年度编制方案与当前年度不一致。不进行复制。");
		}
	}

	private String getRowKey(SuperVO slaveVO) {
		StringBuffer key = new StringBuffer();
		key.append(slaveVO.getAttributeValue("pk_project"));
		key.append(slaveVO.getAttributeValue("pk_fundsource"));
		key.append(slaveVO.getAttributeValue("pk_inoutclass"));
		key.append(slaveVO.getAttributeValue("pk_operation"));
		for (int i = 1; i < 11; i++) {
			key.append(slaveVO.getAttributeValue("defdim"+i));
		}
		return key.toString();
	}


	private List<FormulaInfoVO> generalFormulaInfos(AggBudgetMakeVO aggVo, BudgetcalculateSlaveVO vo,
													AggBudgetcalculateMasterVO aggBudgetcalculateMasterVOs, String topcode, UFBoolean isUseBudgetDept)
			throws BusinessException {
		List<FormulaInfoVO> list = new ArrayList<FormulaInfoVO>();
		// 处理公示，需要查询的业务指标
		//处理公示，将名称公示转换成编码公示，省的改后面的逻辑，还有公示验证类。
		String formula = CalculationFormulaUtils.changeNameFormulaToCodeFormula(vo.getFormula());
		String REGEX = "@(.+?)@";
		Pattern p = Pattern.compile(REGEX);
		Matcher m = p.matcher(String.valueOf(formula));
		StringBuffer operationCode = new StringBuffer();
		this.formulaValues = new HashMap();
		String type = vo.getSrcrowno();
		while (m.find()) {
			operationCode.append(m.group(1));
			operationCode.append(",");
			this.formulaValues.put("@" + m.group(1) + "@", Integer.valueOf(0));
			// modify by wy at 2207适配930
			if (Objects.isNull(type)){
				throw new BusinessException("预算测算设置，数据错误！请到对应的预算测算设置单据，删除原有子表行，重新添加！");
			}

			switch (type){
				case "historydata":
					FormulaInfoVO formulaInfoVOH = new FormulaInfoVO(m.group(1), m.group(1), 3,
							BudgetCalUtil.getQueryDateCondition(aggBudgetcalculateMasterVOs, vo), vo, aggVo, topcode, isUseBudgetDept);
					list.add(formulaInfoVOH);
					break;
				case "businessdata":
					String operationCondition = "code = '" + m.group(1) + "' and dr =0";
					OperationalindicatorMasterVO[] operationalindicatorMasterVO = operationalindicatorMasterVOService
							.listOperationalindicatorMasterVOByCondition(operationCondition);
					FormulaInfoVO formulaInfoVOB = new FormulaInfoVO(operationalindicatorMasterVO[0].getCode(),
							operationalindicatorMasterVO[0].getPk_opeindicato(),
							operationalindicatorMasterVO[0].getOpertype(),
							BudgetCalUtil.getQueryDateCondition(aggBudgetcalculateMasterVOs, vo), vo, aggVo, topcode, isUseBudgetDept);
					list.add(formulaInfoVOB);
					break;
				case "costprodata":
					MetaDataBaseVO metaDataBaseVO = new MetaDataBaseVO();
					metaDataBaseVO.setPk_doc("1001YY1000000011TKDY");
					List<MetaDataBaseVO> vos = LcdpDAO.retrieveByClause(metaDataBaseVO,"pk_extsys = '1001YY1000000011A9RF' " +
							"and code = '"+m.group(1)+"' and isnull(dr,0) = 0");
					if (vos.isEmpty()){
						throw new BusinessException("集成平台返回数据为空："+m.group(1)+"，没有该成本项目。");
					}
					FormulaInfoVO formulaInfoVOC = new FormulaInfoVO(vos.get(0).getAttributeValue("code").toString(),vos.get(0).getPrimaryKey(),
							topcode, aggVo.getParentVO().getPk_budgetdept(),aggVo,BudgetCalUtil.getQueryDateCondition(aggBudgetcalculateMasterVOs, vo));
					list.add(formulaInfoVOC);
					break;
				default:
					break;
			}

//			String operationCondition = "code = '" + m.group(1) + "' and dr =0";
//			if (Arrays.asList(this.queryHisDataFormulas).contains(m.group(1))) {
//
//				FormulaInfoVO formulaInfoVO = new FormulaInfoVO(m.group(1), m.group(1), Integer.valueOf(3),
//						BudgetCalUtil.getQueryDateCondition(aggBudgetcalculateMasterVOs, vo), vo, aggVo, topcode,
//						isUseBudgetDept);
//				list.add(formulaInfoVO);
//				continue;
//			}
//			OperationalindicatorMasterVO[] operationalindicatorMasterVO = this.operationalindicatorMasterVOService
//					.listOperationalindicatorMasterVOByCondition(operationCondition);
//			if (Objects.nonNull(operationalindicatorMasterVO) && operationalindicatorMasterVO.length > 0) {
//
//				FormulaInfoVO formulaInfoVO = new FormulaInfoVO(operationalindicatorMasterVO[0].getCode(),
//						operationalindicatorMasterVO[0].getPk_opeindicato(),
//						operationalindicatorMasterVO[0].getOpertype(),
//						BudgetCalUtil.getQueryDateCondition(aggBudgetcalculateMasterVOs, vo), vo, aggVo, topcode,
//						isUseBudgetDept);
//				list.add(formulaInfoVO);
//			}

		}

		return list;
	}

	private String getStrByDimNonNull(ISuperVO vo) throws DAOException {
		StringBuffer str = new StringBuffer();
		if (Objects.nonNull(vo.getAttributeValue("pk_project"))
				&& !vo.getAttributeValue("pk_project").toString().equals("")) {

			String sql = "select PROJECT_NAME from BD_PROJECT where PK_PROJECT = '"
					+ vo.getAttributeValue("pk_project").toString() + "'";
			String projectName = (String) this.dao.getBaseDAO().executeQuery(sql, new ColumnProcessor());
			str.append(projectName + "，");
		}
		if (Objects.nonNull(vo.getAttributeValue("pk_inoutclass"))
				&& !vo.getAttributeValue("pk_inoutclass").toString().equals("")) {

			String sql = "select name from bd_inoutbusiclass where pk_inoutbusiclass = '"
					+ vo.getAttributeValue("pk_inoutclass").toString() + "'";
			String inoutName = (String) this.dao.getBaseDAO().executeQuery(sql, new ColumnProcessor());
			str.append(inoutName + "，");
		}
		if (Objects.nonNull(vo.getAttributeValue("pk_fundsource"))
				&& !vo.getAttributeValue("pk_fundsource").toString().equals("")) {

			String sql = "select name from bd_fundsource  where pk_fundsource = '"
					+ vo.getAttributeValue("pk_fundsource").toString() + "'";
			String fundsourceName = (String) this.dao.getBaseDAO().executeQuery(sql, new ColumnProcessor());
			str.append(fundsourceName + "，");
		}
		if (Objects.nonNull(vo.getAttributeValue("nyear")) && !vo.getAttributeValue("nyear").toString().equals("")) {
			str.append(vo.getAttributeValue("nyear").toString() + "，");
		}
		if (Objects.nonNull(vo.getAttributeValue("pk_budgetdept"))
				&& !vo.getAttributeValue("pk_budgetdept").toString().equals("")) {

			String sql = "select name from HRPBM_BUDGETDEPT  where pk_budgetdept = '"
					+ vo.getAttributeValue("pk_budgetdept").toString() + "'";
			String deptName = (String) this.dao.getBaseDAO().executeQuery(sql, new ColumnProcessor());
			str.append(deptName + "，");
		}
		return str.toString();
	}
	private boolean checkInoutClassByYearTypeDept(String year, String pk_topbudgettype, String pk_budgetdept)
			throws BusinessException {
		BaseDAO baseDAO = new BaseDAO();
		String sql = " select count(1) from hrpbm_dimassign_inoutclass where isnull(dr,0) = 0 and pk_dimassign in ( " +
				" select pk_dimassign from hrpbm_dimassign where nyear = '" +
				year + "' and pk_budgettype = (select pk_budgettype from hrpbm_budgettype where code = '" + pk_topbudgettype +
				"') and pk_budgetdept = '" + pk_budgetdept + "' and isnull(dr,0) = 0 )";

		ArrayList<Integer> list = (ArrayList<Integer>) baseDAO.executeQuery(sql, new IntegerProcessor());

		return list.get(0) > 0;
	}

}